-
Notifications
You must be signed in to change notification settings - Fork 1
/
api.html
5805 lines (5729 loc) · 216 KB
/
api.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<title>CloudI: A Cloud at the lowest level - API Documentation</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta content="Cloud Framework for fault-tolerant distributed processing with dynamic load balancing" name="description" />
<meta content="api, cloud, private cloud, framework, erlang, fault tolerant, distributed systems, embarrassingly parallel, divide and conquer, cloudi" name="keywords" />
<meta content="global" name="distribution" />
<script src="style.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
<link rel="shortcut icon" href="images/cloud.ico" type="image/x-icon" />
<!-- Open Graph Protocol (OGP) with LinkedIn requirements -->
<meta property="og:title" content="CloudI: A Cloud at the lowest level - API Documentation" />
<meta property="og:description" content="CloudI is an open-source private cloud computing framework for efficient, secure, and internal data processing. CloudI provides scaling for previously unscalable source code with efficient fault-tolerant execution of ATS, C/C++, Erlang/Elixir, Go, Haskell, Java, JavaScript/node.js, OCaml, Perl, PHP, Python, Ruby, or Rust services.
The bare essentials for efficient fault-tolerant processing on a cloud!" />
<meta property="og:image" content="https://cloudi.org/images/cloud_ogp.png" />
<meta property="og:url" content="https://cloudi.org/api.html" />
<meta property="og:type" content="website" />
</head>
<body>
<div id="header">
<a href="index.html">
Cloud<span style="font-family:serif">I</span><img alt="Active Cloud" width="156" height="106" src="images/cloud.png" />
</a>
</div>
<br />
<div id="navigation">
<ul>
<li><a href="api.html" class="active">API</a></li>
<li><a href="faq.html">FAQ</a></li>
<li><a href="tutorials.html">Tutorials</a>
(<a href="tutorial_java.html">Java</a>)</li>
<li><a href="download" rel="noopener" target="_blank">Download</a></li>
<li><a href="https://github.com/CloudI/CloudI/tree/develop#readme">Source</a></li>
<li><a href="support.html">Support</a></li>
</ul>
</div>
<div id="content">
<h1>CloudI API Documentation</h1>
<h3 style="text-align:center">version 2.0.7<br />
last updated on June 8<sup>th</sup> 2024</h3>
<h2 id="Service">CloudI API - Making a Service</h2>
<ul class="api">
<li><a href="#1_Intro" >1.0 - Introduction</a></li>
<li><a href="#1_initialization" >1.1 - (initialization)</a></li>
<li><a href="#1_termination" >1.2 - (termination)</a></li>
<li><a href="#1_subscribe" >1.3 - subscribe</a></li>
<li><a href="#1_subscribe_count" >1.4 - subscribe_count</a></li>
<li><a href="#1_unsubscribe" >1.5 - unsubscribe</a></li>
<li><a href="#1_get_pid" >1.6 - get_pid
(internal services only)</a></li>
<li><a href="#1_get_pids" >1.7 - get_pids
(internal services only)</a></li>
<li><a href="#1_send_sync" >1.8 - send_sync</a></li>
<li><a href="#1_send_async" >1.9 - send_async</a></li>
<li><a href="#1_send_async_active" >1.10 - send_async_active
(internal services only)</a></li>
<li><a href="#1_mcast_async" >1.11 - mcast_async</a></li>
<li><a href="#1_mcast_async_active">1.12 - mcast_async_active
(internal services only)</a></li>
<li><a href="#1_recv_async" >1.13 - recv_async</a></li>
<li><a href="#1_recv_asyncs" >1.14 - recv_asyncs
(internal services only)</a></li>
<li><a href="#1_return" >1.15 - return</a></li>
<li><a href="#1_forward" >1.16 - forward</a></li>
<li><a href="#1_poll" >1.17 - poll
(external services only)</a></li>
<li><a href="#1_shutdown" >1.18 - shutdown</a></li>
</ul>
<h2 id="CloudI">CloudI Service API - Controlling CloudI</h2>
<ul class="api">
<li><a href="#2_Intro" >2.0 - Introduction</a></li>
<li><a href="#2_acl_add" >2.1 - acl_add</a></li>
<li><a href="#2_acl_remove" >2.2 - acl_remove</a></li>
<li><a href="#2_acl" >2.3 - acl</a></li>
<li><a href="#2_service_subscriptions" >2.4 - service_subscriptions</a></li>
<li><a href="#2_services_add" >2.5 - services_add</a></li>
<li><a href="#2_services_remove" >2.6 - services_remove</a></li>
<li><a href="#2_services_restart" >2.7 - services_restart</a></li>
<li><a href="#2_services_suspend" >2.8 - services_suspend</a></li>
<li><a href="#2_services_resume" >2.9 - services_resume</a></li>
<li><a href="#2_services_search" >2.10 - services_search</a></li>
<li><a href="#2_services_status" >2.11 - services_status</a></li>
<li><a href="#2_services_update" >2.12 - services_update</a></li>
<li><a href="#2_services" >2.13 - services</a></li>
<li><a href="#2_nodes_set" >2.14 - nodes_set</a></li>
<li><a href="#2_nodes_get" >2.15 - nodes_get</a></li>
<li><a href="#2_nodes_add" >2.16 - nodes_add</a></li>
<li><a href="#2_nodes_remove" >2.17 - nodes_remove</a></li>
<li><a href="#2_nodes_alive" >2.18 - nodes_alive</a></li>
<li><a href="#2_nodes_dead" >2.19 - nodes_dead</a></li>
<li><a href="#2_nodes_status" >2.20 - nodes_status</a></li>
<li><a href="#2_nodes_status_reset" >2.21 - nodes_status_reset (new in 2.0.8)</a></li>
<li><a href="#2_nodes" >2.22 - nodes</a></li>
<li><a href="#2_logging_set" >2.23 - logging_set</a></li>
<li><a href="#2_logging_file_set" >2.24 - logging_file_set</a></li>
<li><a href="#2_logging_level_set" >2.25 - logging_level_set</a></li>
<li><a href="#2_logging_stdout_set" >2.26 - logging_stdout_set</a></li>
<li><a href="#2_logging_syslog_set" >2.27 - logging_syslog_set</a></li>
<li><a href="#2_logging_formatters_set">2.28 - logging_formatters_set</a></li>
<li><a href="#2_logging_redirect_set" >2.29 - logging_redirect_set</a></li>
<li><a href="#2_logging_status" >2.30 - logging_status</a></li>
<li><a href="#2_logging_status_reset" >2.31 - logging_status_reset</a></li>
<li><a href="#2_logging" >2.32 - logging</a></li>
<li><a href="#2_code_path_add" >2.33 - code_path_add</a></li>
<li><a href="#2_code_path_remove" >2.34 - code_path_remove</a></li>
<li><a href="#2_code_path" >2.35 - code_path</a></li>
<li><a href="#2_code_status" >2.36 - code_status</a></li>
<li><a href="#2_code_status_reset" >2.37 - code_status_reset (new in 2.0.8)</a></li>
</ul>
<hr>
<h2>CloudI API - Making a Service</h2>
<h3 id="1_Intro">1.0 - Introduction</h3>
<p class="paragraph">
The CloudI API provides a simple messaging API which allows CloudI services
to send requests. The CloudI API supports both publish/subscribe and
request/reply communication in an intuitive way. It is not necessary to
understand the Erlang programming language (or Elixir), to use the
CloudI API since a full CloudI API implementation is provided for every
supported programming language (ATS, C/C++, Elixir, Erlang, Go, Haskell,
Java, JavaScript, OCaml, Perl, PHP, Python, Ruby, and Rust, currently).
</p>
<p class="paragraph">
The CloudI API messaging is different from other messaging APIs and
provides simpler integration for a few reasons:
</p>
<ul>
<li>CloudI API usage requires CloudI usage as an application server to enforce fault-tolerance and scalability constraints on source code execution</li>
<li>The CloudI service that receives a request determines whether a reply occurs (returning no response data is the same as not providing a reply)</li>
<li>All required callbacks are minimal (only a single request callback is necessary for a CloudI service to handle requests) to keep CloudI services simpler, so they are less error-prone than other solutions</li>
<li>Requests are not persisted to database storage to avoid persisting errors since errors are often transient and only relate to a specific context</li>
<li>All CloudI API programming language integration makes CloudI services first-class processes within the Erlang VM to provide consistent functionality and fault tolerance</li>
<li>Every CloudI API request contains a priority</li>
<li>Every CloudI API request contains a unique v1 UUID for identifying the request and its response</li>
<li>Every CloudI API request contains a timeout which is updated based on the queuing and processing delays the request encounters</li>
</ul>
<p class="paragraph">
The <a href="#1_subscribe">subscribe</a> function subscribes to a
service name pattern string which may contain "*" and "?" wildcard
characters, to accept any matching service requests. Either
"*" or "?" in a service name pattern will match one or more characters
with "?" never matching the character that follows it
("?" is unable to be the last character, i.e.,
"/?/" matches "/a/" but never "/a/b/" while "/*/" will match either).
The <a href="#1_send_sync">send_sync</a> function and the
<a href="#1_send_async">send_async</a> function provide point-to-point
communication based on the service name provided. When multiple services
<a href="#1_subscribe">subscribe</a> with the same service name pattern
the destination is picked based on the sending service's "destination
refresh method", which can be any of the following:
</p>
<table id="1_Intro_dest"><tr><th>
Destination Refresh Method
</th><th>
Meaning
</th></tr><tr><td>
lazy_closest (or)<br /> immediate_closest
</td><td>
A service running on the local node will be selected,
unless the destination only exists on a remote node
</td></tr><tr><td>
lazy_furthest (or)<br /> immediate_furthest
</td><td>
A service running on a remote node will be selected,
unless the destination only exists on the local node
</td></tr><tr><td>
lazy_random (or)<br /> immediate_random
</td><td>
A service is selected randomly from the subscribed services
</td></tr><tr><td>
lazy_local (or)<br /> immediate_local
</td><td>
Only a service on the local node is selected
</td></tr><tr><td>
lazy_remote (or)<br /> immediate_remote
</td><td>
Only a service on a remote node is selected
</td></tr><tr><td>
lazy_newest (or)<br /> immediate_newest
</td><td>
Only the most recently subscribed service is selected
</td></tr><tr><td>
lazy_oldest (or)<br /> immediate_oldest
</td><td>
Only the first subscribed service is selected
</td></tr><tr><td>
none
</td><td>
The service should never send a request and it is an error when the
service attempts to send (the service may still receive requests)
</td></tr></table>
<p class="paragraph">
The "lazy" prefix and the "immediate" prefix on the destination refresh
method determines whether stale data is used within the service's data
or if a single lookup process is used to get the most current
destination result, respectively ("lazy" is for when long-lived services
are the destination but consumes more service memory, and "immediate" is
for when short-lived services are the destination but creates contention
for the lookup process).
</p>
<p class="paragraph">
When separate service processes subscribe with the same service name
pattern, each subscription is used based on random selection
(if more than one service processes are available based on the
destination refresh method), when a service request is sent to the
service name. If the same service subscribes with the same
service name pattern more than once within a single external service
thread, each subscription is used in round-robin order
(first subscription is called first, so order is preserved),
when the service thread receives a request for the specific
service name pattern.
</p>
<p class="paragraph">
The <a href="#1_mcast_async">mcast_async</a> function provides
publish functionality by sending a request asynchronously to all
services that have <a href="#1_subscribe">subscribe</a>d to the same
service name pattern. To receive an asynchronous request
<a href="#1_recv_async">recv_async</a> is used with the "TransId"
(i.e., Transaction Id, a v1 UUID) or a null UUID to receive the
oldest service request.
</p>
<p class="paragraph">
The <a href="#1_return">return</a> function is used to respond to a
service request and terminate the current request handler
(i.e., the service request is finished, at that point).
A service can <a href="#1_return">return</a> a
<a href="faq.html#4_Null">null response</a> if the sending
service should not receive a response, which can be used for typical
response-less publish functionality.
The <a href="#1_forward">forward</a>
function provides a new destination for the same service request,
delaying the request's completion, but still terminating the current
request handler.
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_initialization">1.1 - (initialization)</h3>
<p class="paragraph">
The service configuration will control the CloudI API initialization,
which is done automatically, but does influence the source code.
The service configuration defines the number of Operating System (OS)
processes to create and
the number of threads for an external service. For an internal service,
the configuration defines the number of Erlang processes to create.
A number specified as an integer in the configuration is the exact
number of processes or threads.
However, if the number is specified as a floating point number, it is used
as a CPU count (i.e., Erlang scheduler count) multipler where >1.0
implies floor and <1.0 implies round. The external service
APIs provide the thread_count function so that the total number of threads
can be used for thread creation, with each thread holding an instance of
the CloudI API (to avoid lock contention):
</p>
<div class="tabs" style="min-height: 13em;">
<div id="1_initialization_C">
<a href="#1_initialization_C">C</a>
<div class="tab_contents">
<pre class="code">
int cloudi_initialize_thread_count(unsigned int * const thread_count);
int cloudi_initialize(cloudi_instance_t * api,
unsigned int const thread_index,
void * state);
</pre>
</div>
</div> <!-- C -->
<div id="1_initialization_CXX">
<a href="#1_initialization_CXX">C++</a>
<div class="tab_contents">
<pre class="code">
unsigned int CloudI::API::thread_count();
CloudI::API(unsigned int const thread_index,
bool const terminate_return_value = true);
</pre>
</div>
</div> <!-- C++ -->
<div id="1_initialization_Elixir">
<a href="#1_initialization_Elixir">Elixir</a>
<div class="tab_contents">
<pre class="code">
def cloudi_service_init(_args, _prefix, _timeout, dispatcher) do
# ...
{:ok, :undefined}
end
</pre>
</div>
</div> <!-- Elixir -->
<div id="1_initialization_Erlang">
<a href="#1_initialization_Erlang">Erlang</a>
<div class="tab_contents">
<pre class="code">
cloudi_service_init(_Args, _Prefix, _Timeout, Dispatcher) ->
% ...
{ok, #state{}}.
</pre>
</div>
</div> <!-- Erlang -->
<div id="1_initialization_Go">
<a href="#1_initialization_Go">Go</a>
<div class="tab_contents">
<pre class="code">
cloudi.ThreadCount() (uint32, error)
cloudi.API(threadIndex uint32, state interface{}) (*Instance, error)
</pre>
</div>
</div> <!-- Go -->
<div id="1_initialization_Java">
<a href="#1_initialization_Java">Java</a>
<div class="tab_contents">
<pre class="code">
int org.cloudi.API.thread_count();
org.cloudi.API(final int thread_index);
</pre>
</div>
</div> <!-- Java -->
<div id="1_initialization_JavaScript">
<a href="#1_initialization_JavaScript">JavaScript</a>
<div class="tab_contents">
<pre class="code">
CloudI.API.thread_count();
CloudI.API(thread_index, callback);
</pre>
</div>
</div> <!-- JavaScript -->
<div id="1_initialization_Perl">
<a href="#1_initialization_Perl">Perl</a>
<div class="tab_contents">
<pre class="code">
CloudI::API->thread_count();
CloudI::API->new($thread_index);
</pre>
</div>
</div> <!-- Perl -->
<div id="1_initialization_PHP">
<a href="#1_initialization_PHP">PHP</a>
<div class="tab_contents">
<pre class="code">
\CloudI\API::thread_count();
\CloudI\API($thread_index);
</pre>
</div>
</div> <!-- PHP -->
<div id="1_initialization_Python">
<a href="#1_initialization_Python">Python</a>
<div class="tab_contents">
<pre class="code">
cloudi.API.thread_count()
cloudi.API(thread_index)
</pre>
</div>
</div> <!-- Python -->
<div id="1_initialization_Ruby">
<a href="#1_initialization_Ruby">Ruby</a>
<div class="tab_contents">
<pre class="code">
CloudI::API.thread_count()
CloudI::API.new(thread_index)
</pre>
</div>
</div> <!-- Ruby -->
<div id="1_initialization_code">
<a href="#1_initialization_code"> </a>
<div class="tab_contents">
Initialize an instance of the CloudI API
</div>
</div> <!-- Description -->
</div>
<p id="1_initialization_timeout" class="paragraph">
An internal service uses the configured initialization timeout to limit the
execution time spent within the cloudi_service_init/4 cloudi_service
behaviour callback function. An external service uses the configured
initialization timeout to limit the execution time spent between
creating an instance of the CloudI API and calling the CloudI API
<a href="#1_poll">poll</a> function (for the first time).
During the service initialization the CloudI API functions that may not be
called are:
<a href="#1_send_sync">send_sync</a>,
<a href="#1_recv_async">recv_async</a>,
<a href="#1_return">return</a> and
<a href="#1_forward">forward</a>
(i.e., send_sync and recv_async block to receive a service request response
but service initialization must be asynchronous and within the
initialization timeout period, return and forward are only valid
when completing the handling of a service request).
</p>
<p class="paragraph">
If the initialization timeout is exceeded a service failure has
occurred and a restart will occur (if possible) based on the configured
MaxR (maximum restarts) and MaxT (maximum time period in seconds) service
configuration values. If the service was configured in the
CloudI configuration file (i.e., <a href="https://github.com/CloudI/CloudI/blob/master/src/cloudi_minimal.conf.in" rel="noopener" target="_blank">/usr/local/etc/cloudi/cloudi.conf</a>,
used when CloudI is first started) and one of
the configured services fails initialization MaxR times, CloudI will
shutdown to prevent erroneous operation. To avoid the fail-fast
handling of the CloudI configuration file, the CloudI Service API
<a href="#2_services_add">services_add</a> function may be used
to provide service configuration (the return value will provide
information about service initialization failures exceeding MaxR).
</p>
<p class="paragraph">
The service configuration also allows Access Control Lists (ACLs) to define
explicit service name patterns for allowing or denying service
destinations when the service sends a service request. The ACLs along
with the destination refresh method determine how service requests are
sent while other <a href="#2_services_add_config_opts">service options</a>
can tweak default settings.
</p>
<p class="paragraph">
External (non-Erlang) services are provided both the command line and
the environmental variables specified within the service configuration.
External sevice configuration uses the full path to the executable while
internal services use the module name (and the OTP application name)
within the code search paths. All environmental variables set in the
shell executing the Erlang VM can be used within the executable path,
arguments and environment set in the configuration of an external service,
using standard shell syntax (e.g., "${USER}" or "$USER",
where "\\$" is a literal "$" character).
</p>
<p>
Please see <a href="#2_services_add">the CloudI Service API (services_add)</a>
for more details about service configuration.
<br /><br />
Specific Language Integration Notes:
</p>
<p class="paragraph">
The Elixir/Erlang CloudI API functions shown below accept the most function
parameters in cloudi_service but functions with less parameters do
exist and they utilize default values for timeouts and request
priority. Both the Timeout parameter and the Priority parameter
accept the 'undefined' atom to assign the default configured value.
Please see the
<a href="api/cloudi_core-2.0.7/cloudi_service.html#index" target="_blank">cloudi_service module</a>
to see all the available functions and the behavior interface functions
that are implemented within an Erlang service. The cloudi_service module
is used within CloudI services, however, it is also possible to use CloudI
services from external Erlang processes with a subset of the CloudI API
functions in the
<a href="api/cloudi_core-2.0.7/cloudi.html#index" target="_blank">cloudi module</a>.
</p>
<p class="paragraph">
Both the C and the C++ CloudI API rely on the same underlying code, with
the C++ API object as a wrapper around the C API pointer, so there should
be no large performance difference. STL is avoided, to avoid the
libstdc++ memory pool and internal memory pools are used. The C++
CloudI API functions below use the STRING type to represent either
char const * const (or) std::string const &, since both are
supported with overloaded functions.
</p>
<p class="paragraph">
The Java CloudI API doesn't have any C or C++ integration. It only uses
reflection to utilize the low-level file descriptor object and
store object function pointers.
</p>
<p class="paragraph">
The python CloudI API is provided as both the "cloudi" module and the
"cloudi_c" module. The "cloudi_c" module uses the C++ CloudI API for
more efficiency, while the "cloudi" module only uses Python source code.
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_termination">1.2 - (termination)</h3>
<p class="paragraph">
An internal service uses the termination timeout to limit the
execution time spent within the cloudi_service_terminate/3 cloudi_service
behaviour callback function. An external service uses the
termination timeout to limit the execution time spent between
returning from the CloudI API
<a href="#1_poll">poll</a> function and the service OS process exit.
The termination timout is slightly less than
MaxT (maximum time period in seconds) divided by MaxR (maximum restarts)
to ensure service failures are finite
(MaxR and MaxT are both service configuration values).
During termination no CloudI API functions may be called.
The termination execution time is used to cleanup the service's
state (e.g., close connections or files).
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_subscribe">1.3 - subscribe</h3>
<div class="tabs" style="min-height: 43em;">
<div id="1_subscribe_C">
<a href="#1_subscribe_C">C</a>
<div class="tab_contents">
<pre class="code">
typedef void (*cloudi_callback_t)(int const request_type,
char const * const name,
char const * const pattern,
void const * const request_info,
uint32_t const request_info_size,
void const * const request,
uint32_t const request_size,
uint32_t timeout,
int8_t priority,
char const * const trans_id,
char const * const source,
uint32_t const source_size,
void * state,
cloudi_instance_t * api);
int cloudi_subscribe(cloudi_instance_t * api,
char const * const pattern,
cloudi_callback_t f);
</pre>
</div>
</div> <!-- C -->
<div id="1_subscribe_CXX">
<a href="#1_subscribe_CXX">C++</a>
<div class="tab_contents">
<pre class="code">
template <typename T>
int CloudI::API::subscribe(STRING pattern,
T & object,
void (T::*f) (CloudI::API const &,
int const,
STRING,
STRING,
void const * const,
uint32_t const,
void const * const,
uint32_t const,
uint32_t,
int8_t,
char const * const,
char const * const,
uint32_t const)) const;
int CloudI::API::subscribe(STRING pattern,
void (*f) (API const &,
int const,
STRING,
STRING,
void const * const,
uint32_t const,
void const * const,
uint32_t const,
uint32_t,
int8_t,
char const * const,
char const * const,
uint32_t const)) const
</pre>
</div>
</div> <!-- C++ -->
<div id="1_subscribe_Elixir">
<a href="#1_subscribe_Elixir">Elixir</a>
<div class="tab_contents">
<pre class="code">
:cloudi_service.subscribe(dispatcher, pattern)
</pre>
</div>
</div> <!-- Elixir -->
<div id="1_subscribe_Erlang">
<a href="#1_subscribe_Erlang">Erlang</a>
<div class="tab_contents">
<pre class="code">
cloudi_service:subscribe(Dispatcher :: pid(), Pattern :: string()) ->
ok.
</pre>
</div>
</div> <!-- Erlang -->
<div id="1_subscribe_Go">
<a href="#1_subscribe_Go">Go</a>
<div class="tab_contents">
<pre class="code">
func (api *cloudi.Instance) Subscribe(pattern string,
function cloudi.Callback) error
</pre>
</div>
</div> <!-- Go -->
<div id="1_subscribe_Java">
<a href="#1_subscribe_Java">Java</a>
<div class="tab_contents">
<pre class="code">
void org.cloudi.API.subscribe(final String pattern,
final Object instance,
final String methodName);
// with Java ≥ 8 a method reference can be used
void org.cloudi.API.subscribe(final String pattern,
final FunctionInterface9 callback);
</pre>
</div>
</div> <!-- Java -->
<div id="1_subscribe_JavaScript">
<a href="#1_subscribe_JavaScript">JavaScript</a>
<div class="tab_contents">
<pre class="code">
var callback = function () {};
CloudI.API.subscribe(pattern, object, object_function, callback);
</pre>
</div>
</div> <!-- JavaScript -->
<div id="1_subscribe_Perl">
<a href="#1_subscribe_Perl">Perl</a>
<div class="tab_contents">
<pre class="code">
CloudI::API->subscribe($pattern, $function);
CloudI::API->subscribe($pattern, $object, $method);
</pre>
</div>
</div> <!-- Perl -->
<div id="1_subscribe_PHP">
<a href="#1_subscribe_PHP">PHP</a>
<div class="tab_contents">
<pre class="code">
\CloudI\API::subscribe($pattern, $object, $method);
</pre>
</div>
</div> <!-- PHP -->
<div id="1_subscribe_Python">
<a href="#1_subscribe_Python">Python</a>
<div class="tab_contents">
<pre class="code">
cloudi.API.subscribe(pattern, function)
</pre>
</div>
</div> <!-- Python -->
<div id="1_subscribe_Ruby">
<a href="#1_subscribe_Ruby">Ruby</a>
<div class="tab_contents">
<pre class="code">
CloudI::API.subscribe(pattern, function)
</pre>
</div>
</div> <!-- Ruby -->
<div id="1_subscribe_code">
<a href="#1_subscribe_code"> </a>
<div class="tab_contents">
Subscribe to a service name pattern
</div>
</div> <!-- Description -->
</div>
<p class="paragraph">
Subscribes with a service name pattern which provides a destination for
other services to send to. The subscribing service will receive a
service request, if a different service sends a service request with a
service name that matches the service name pattern. The service name
pattern is a string that may contain "*" and "?" wildcard characters,
to accept any matching service requests. Either "*" or "?" in a
service name pattern will match one or more characters
with "?" never matching the character that follows it
("?" is unable to be the last character, i.e.,
"/?/" matches "/a/" but never "/a/b/" while "/*/" will match either).
The service names and service name patterns are expected to be in a
filepath format (e.g., "/root/directory/file.extension") by some
provided CloudI services, though nothing enforces this convention.
Good design dictates that service names operate within a given scope.
Both the service names and the service name patterns should represent
an appropriate scope, which the service manages
(i.e., the same concept as a
<a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier" rel="noreferrer" target="_blank">Uniform Resource Identifier (URI)</a>).
</p>
<p class="paragraph">
When a service subscribes to a service name pattern, the supplied pattern
string is appended to the service name prefix from the service's
configuration, to provide the full service name pattern. The prefix
provided within the service's configuration declares the scope of all
service operations, as they are seen from other running services.
Multiple subscribe function calls can increase the probability of
receiving a service request when other services are subscribed with the
same service name pattern.
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_subscribe_count">1.4 - subscribe_count</h3>
<div class="tabs" style="min-height: 12em;">
<div id="1_subscribe_count_C">
<a href="#1_subscribe_count_C">C</a>
<div class="tab_contents">
<pre class="code">
int cloudi_subscribe_count(cloudi_instance_t * api,
char const * const pattern);
// cloudi_get_subscribe_count(p) to get the result
</pre>
</div>
</div> <!-- C -->
<div id="1_subscribe_count_CXX">
<a href="#1_subscribe_count_CXX">C++</a>
<div class="tab_contents">
<pre class="code">
int CloudI::API::subscribe_count(STRING pattern) const;
// CloudI::API::get_subscribe_count() to get the result
</pre>
</div>
</div> <!-- C++ -->
<div id="1_subscribe_count_Elixir">
<a href="#1_subscribe_count_Elixir">Elixir</a>
<div class="tab_contents">
<pre class="code">
:cloudi_service.subscribe_count(dispatcher, pattern)
</pre>
</div>
</div> <!-- Elixir -->
<div id="1_subscribe_count_Erlang">
<a href="#1_subscribe_count_Erlang">Erlang</a>
<div class="tab_contents">
<pre class="code">
cloudi_service:subscribe_count(Dispatcher :: pid(),
Pattern :: string()) ->
non_neg_integer().
</pre>
</div>
</div> <!-- Erlang -->
<div id="1_subscribe_count_Go">
<a href="#1_subscribe_count_Go">Go</a>
<div class="tab_contents">
<pre class="code">
func (api *cloudi.Instance) SubscribeCount(pattern string)
(uint32, error)
</pre>
</div>
</div> <!-- Go -->
<div id="1_subscribe_count_Java">
<a href="#1_subscribe_count_Java">Java</a>
<div class="tab_contents">
<pre class="code">
int org.cloudi.API.subscribe_count(final String pattern);
// return value is result
</pre>
</div>
</div> <!-- Java -->
<div id="1_subscribe_count_JavaScript">
<a href="#1_subscribe_count_JavaScript">JavaScript</a>
<div class="tab_contents">
<pre class="code">
var callback = function (count) {};
CloudI.API.subscribe_count(pattern, callback);
</pre>
</div>
</div> <!-- JavaScript -->
<div id="1_subscribe_count_Perl">
<a href="#1_subscribe_count_Perl">Perl</a>
<div class="tab_contents">
<pre class="code">
CloudI::API->subscribe_count($pattern);
</pre>
</div>
</div> <!-- Perl -->
<div id="1_subscribe_count_PHP">
<a href="#1_subscribe_count_PHP">PHP</a>
<div class="tab_contents">
<pre class="code">
\CloudI\API::subscribe_count($pattern);
</pre>
</div>
</div> <!-- PHP -->
<div id="1_subscribe_count_Python">
<a href="#1_subscribe_count_Python">Python</a>
<div class="tab_contents">
<pre class="code">
cloudi.API.subscribe_count(pattern)
# return value is result
</pre>
</div>
</div> <!-- Python -->
<div id="1_subscribe_count_Ruby">
<a href="#1_subscribe_count_Ruby">Ruby</a>
<div class="tab_contents">
<pre class="code">
CloudI::API.subscribe_count(pattern)
# return value is result
</pre>
</div>
</div> <!-- Ruby -->
<div id="1_subscribe_count_code">
<a href="#1_subscribe_count_code"> </a>
<div class="tab_contents">
Determine how many subscriptions has occurred with a service name pattern
</div>
</div> <!-- Description -->
</div>
<p class="paragraph">
Provide a count of how many times a subscription has occurred for a
specific service name pattern with the current service process.
Often the result is either 0 or 1, but it is possible to subscribe any
number of times to change the probability of the service process getting
a service request, when many service processes are subscribing with the
same service name. This function will always check the authoritative
service process registry, so the result is always correct at that
point in time (i.e., a lazy destination refresh method will not affect
the subscribe_count result).
</p>
<p class="paragraph">
subscribe_count would be most common during testing and first learning
about CloudI, but the function may also be used if the subscribe function
usage is complex and not tracked separately (i.e., tracked within the
service process' internal state).
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_unsubscribe">1.5 - unsubscribe</h3>
<div class="tabs" style="min-height: 11em;">
<div id="1_unsubscribe_C">
<a href="#1_unsubscribe_C">C</a>
<div class="tab_contents">
<pre class="code">
int cloudi_unsubscribe(cloudi_instance_t * api,
char const * const pattern);
</pre>
</div>
</div> <!-- C -->
<div id="1_unsubscribe_CXX">
<a href="#1_unsubscribe_CXX">C++</a>
<div class="tab_contents">
<pre class="code">
int CloudI::API::unsubscribe(STRING pattern) const;
</pre>
</div>
</div> <!-- C++ -->
<div id="1_unsubscribe_Elixir">
<a href="#1_unsubscribe_Elixir">Elixir</a>
<div class="tab_contents">
<pre class="code">
:cloudi_service.unsubscribe(dispatcher, pattern)
</pre>
</div>
</div> <!-- Elixir -->
<div id="1_unsubscribe_Erlang">
<a href="#1_unsubscribe_Erlang">Erlang</a>
<div class="tab_contents">
<pre class="code">
cloudi_service:unsubscribe(Dispatcher :: pid(), Pattern :: string()) ->
ok.
</pre>
</div>
</div> <!-- Erlang -->
<div id="1_unsubscribe_Go">
<a href="#1_unsubscribe_Go">Go</a>
<div class="tab_contents">
<pre class="code">
func (api *cloudi.Instance) Unsubscribe(pattern string) error
</pre>
</div>
</div> <!-- Go -->
<div id="1_unsubscribe_Java">
<a href="#1_unsubscribe_Java">Java</a>
<div class="tab_contents">
<pre class="code">
void org.cloudi.API.unsubscribe(final String pattern);
</pre>
</div>
</div> <!-- Java -->
<div id="1_unsubscribe_JavaScript">
<a href="#1_unsubscribe_JavaScript">JavaScript</a>
<div class="tab_contents">
<pre class="code">
var callback = function () {};
CloudI.API.unsubscribe(pattern, callback);
</pre>
</div>
</div> <!-- JavaScript -->
<div id="1_unsubscribe_Perl">
<a href="#1_unsubscribe_Perl">Perl</a>
<div class="tab_contents">
<pre class="code">
CloudI::API->unsubscribe($pattern);
</pre>
</div>
</div> <!-- Perl -->
<div id="1_unsubscribe_PHP">
<a href="#1_unsubscribe_PHP">PHP</a>
<div class="tab_contents">
<pre class="code">
\CloudI\API::unsubscribe($pattern);
</pre>
</div>
</div> <!-- PHP -->
<div id="1_unsubscribe_Python">
<a href="#1_unsubscribe_Python">Python</a>
<div class="tab_contents">
<pre class="code">
cloudi.API.unsubscribe(pattern)
</pre>
</div>
</div> <!-- Python -->
<div id="1_unsubscribe_Ruby">
<a href="#1_unsubscribe_Ruby">Ruby</a>
<div class="tab_contents">
<pre class="code">
CloudI::API.unsubscribe(pattern)
</pre>
</div>
</div> <!-- Ruby -->
<div id="1_unsubscribe_code">
<a href="#1_unsubscribe_code"> </a>
<div class="tab_contents">
Unsubscribe from a service name pattern
</div>
</div> <!-- Description -->
</div>
<p class="paragraph">
Unsubscribe will remove the service's subscription for the specific
service name pattern. If a service has subscribed with the same service
name pattern multiple times, the unsubscribe will only remove one
subscription instance. The subscription instance which is removed
is whatever subscription would have been called next, for a matching
service request.
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_get_pid">1.6 - get_pid (internal services only)</h3>
<div class="tabs" style="min-height: 15em;">
<div id="1_get_pid_Elixir">
<a href="#1_get_pid_Elixir">Elixir</a>
<div class="tab_contents">
<pre class="code">
:cloudi_service.get_pid(dispatcher, name, timeout)
</pre>
</div>
</div> <!-- Elixir -->
<div id="1_get_pid_Erlang">
<a href="#1_get_pid_Erlang">Erlang</a>
<div class="tab_contents">
<pre class="code">
cloudi_service:get_pid(Dispatcher :: pid(),
Name :: string(),
Timeout :: non_neg_integer() | 'undefined' |
'limit_min' | 'limit_max') ->
{'ok', PatternPid :: {string(), pid()}} |
{'error', Reason :: atom()}.
</pre>
</div>
</div> <!-- Erlang -->
<div id="1_get_pid_code">
<a href="#1_get_pid_code"> </a>
<div class="tab_contents">
Get a service process identifier for a service whose service name
pattern subscription matches the provided service name
</div>
</div> <!-- Description -->
</div>
<p class="paragraph">
Internal (Elixir/Erlang-only) services can request an Erlang process
based on the service name provided, before calling either the
send_sync function or the send_async function. The get_pid
function should rarely be necessary, but it can allow other logic
to be used for determining which service should receive a request
(e.g., based on apparent processing power, like within the hexpi test).
The Erlang PatternPid tuple returned could become invalid if the service
destination terminated, so the Erlang process monitoring becomes
the burden of the get_pid function user. Due to the intimate nature
of this function, it only exists within the Elixir/Erlang CloudI API
(to implement it in other languages would cause service destination
inconsistencies due to the function delay and the potential storage
before the destination is used).
</p>
<p class="paragraph">
The get_pid function provides a way to split the service name lookup
latency from the service request latency so that two separate timeout
values can be used, instead of a single timeout.
</p>
<div class="top"><a href="#Service">Top</a></div>
<h3 id="1_get_pids">1.7 - get_pids (internal services only)</h3>
<div class="tabs" style="min-height: 15em;">
<div id="1_get_pids_Elixir">
<a href="#1_get_pids_Elixir">Elixir</a>
<div class="tab_contents">
<pre class="code">
:cloudi_service.get_pids(dispatcher, name, timeout)
</pre>
</div>
</div> <!-- Elixir -->
<div id="1_get_pids_Erlang">
<a href="#1_get_pids_Erlang">Erlang</a>
<div class="tab_contents">
<pre class="code">
cloudi_service:get_pids(Dispatcher :: pid(),
Name :: string(),
Timeout :: non_neg_integer() | 'undefined' |
'limit_min' | 'limit_max') ->
{'ok', PatternPids :: nonempty_list({string(), pid()})} |
{'error', Reason :: atom()}.
</pre>
</div>
</div> <!-- Erlang -->
<div id="1_get_pids_code">
<a href="#1_get_pids_code"> </a>
<div class="tab_contents">
Get all service process identifiers for services whose service name
pattern subscriptions match the provided service name
</div>
</div> <!-- Description -->
</div>
<p class="paragraph">
Internal (Elixir/Erlang-only) services can request a list of Erlang
processes based on the service name provided, before calling either the
send_sync function or the send_async function. If all Erlang processes
returned need to be used with send_async, it is easier to use the
<a href="#1_mcast_async">mcast_async</a> function. The get_pids
function should rarely be necessary, but it can allow other logic
to be used for determining which service should receive a request
(e.g., based on apparent processing power, like within the hexpi test).
The Erlang PatternPids tuple list returned could contain invalid
Erlang processes if the service destination terminated, so the
Erlang process monitoring becomes