Class: Tupelo::AppBuilder
- Defined in:
- lib/tupelo/app/trace.rb,
lib/tupelo/app/remote.rb,
lib/tupelo/app/builder.rb
Overview
Not an essential part of the library, but used to build up groups of processes for use in examples, tests, benchmarks, etc.
Instance Attribute Summary collapse
-
#argv ⇒ Object
readonly
Arguments available to application after tupelo has parsed out switches and args that it recognizes.
-
#ez ⇒ Object
readonly
Returns the value of attribute ez.
-
#owns_services ⇒ Object
readonly
Does this app own (as child processes) the seq, cseq, and arc services?.
-
#tunnel_default ⇒ Object
readonly
Do remote clients default to using ssh tunnels for data? This has slightly different meanings in two cases:.
Instance Method Summary collapse
-
#child(client_class = Client, passive: false, **opts, &block) ⇒ Object
Yields a client that runs in a subprocess.
-
#initialize(ez, argv: argv, owns_services: nil, tunnel_default: false) ⇒ AppBuilder
constructor
A new instance of AppBuilder.
-
#local(client_class = Client, **opts, &block) ⇒ Object
Yields a client that runs in this process.
- #log ⇒ Object
-
#remote(client_class = Client, client_lib: 'tupelo/client', host: nil, **opts) ⇒ Object
Perform client operations on another host.
- #run_client(client_class, opts) ⇒ Object
- #start_trace ⇒ Object
Constructor Details
#initialize(ez, argv: argv, owns_services: nil, tunnel_default: false) ⇒ AppBuilder
Returns a new instance of AppBuilder.
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/tupelo/app/builder.rb', line 31 def initialize ez, argv: argv, owns_services: nil, tunnel_default: false @ez = ez @owns_services = owns_services @tunnel_default = tunnel_default @argv = argv # When connecting to remote, non-sibling (not started by the same ancestor # process) services, use a tunnel if requested to (see note under # #tunnel_default). if not owns_services and tunnel_default and not ez.sibling ez.tunnel_to_remote_services end end |
Instance Attribute Details
#argv ⇒ Object (readonly)
Arguments available to application after tupelo has parsed out switches and args that it recognizes.
29 30 31 |
# File 'lib/tupelo/app/builder.rb', line 29 def argv @argv end |
#ez ⇒ Object (readonly)
Returns the value of attribute ez.
5 6 7 |
# File 'lib/tupelo/app/builder.rb', line 5 def ez @ez end |
#owns_services ⇒ Object (readonly)
Does this app own (as child processes) the seq, cseq, and arc services?
8 9 10 |
# File 'lib/tupelo/app/builder.rb', line 8 def owns_services @owns_services end |
#tunnel_default ⇒ Object (readonly)
Do remote clients default to using ssh tunnels for data? This has slightly different meanings in two cases:
-
When the client is started by the #remote method, as in many simpler examples, the #tunnel_default is the default for the tunnel keyword argument of the #remote method. (Uses ssh -R.)
-
When the client is started as an unrelated process (for example, connecting to a pre-existing tupelo cluster running on a different host), there is no #remote call, and tunneling is automatically set up. (Uses ssh -L.)
In both cases, the –tunnel command line switch sets tunnel_default to true.
25 26 27 |
# File 'lib/tupelo/app/builder.rb', line 25 def tunnel_default @tunnel_default end |
Instance Method Details
#child(client_class = Client, passive: false, **opts, &block) ⇒ Object
Yields a client that runs in a subprocess.
A passive client will be forced to stop after all active clients exit. Use the passive flag for processes that wait for tuples and respond in some way. Then you do not have to manually interrupt the whole application when the active processes are done. See examples.
Returns pid of child process.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/tupelo/app/builder.rb', line 73 def child client_class = Client, passive: false, **opts, &block ez.child :seqd, :cseqd, :arcd, passive: passive do |seqd, cseqd, arcd| opts = {seq: seqd, cseq: cseqd, arc: arcd, log: log}.merge(opts) run_client client_class, **opts do |client| if block if block.arity == 0 client.instance_eval &block else yield client end end end end end |
#local(client_class = Client, **opts, &block) ⇒ Object
Yields a client that runs in this process.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/tupelo/app/builder.rb', line 50 def local client_class = Client, **opts, &block ez.local :seqd, :cseqd, :arcd do |seqd, cseqd, arcd| opts = {seq: seqd, cseq: cseqd, arc: arcd, log: log}.merge(opts) run_client client_class, **opts do |client| if block if block.arity == 0 client.instance_eval &block else yield client end end end end end |
#log ⇒ Object
45 46 47 |
# File 'lib/tupelo/app/builder.rb', line 45 def log ez.log end |
#remote(client_class = Client, client_lib: 'tupelo/client', host: nil, **opts) ⇒ Object
Perform client operations on another host.
There are two modes: drb and eval. In the drb mode, a block executes locally, performing tuplespace operations by proxy to the remote tupelo client instance. Results of the ops are available in the local process. This is very useful for testing and examples.
In the eval mode, a string is evaluated on the remote host in the context of a client instance.
There are some minor limitations compared to #child:
In eval mode, the code string is always treated as in the arity 0 case of #child, in other words “DSL mode”, in other words the self is the client.
Unlike #child, there is no mode that returns a Client instance.
Note that EasyServe options apply, including the ‘tunnel: true` option. The default for this option is true if the `–tunnel` switch is present on the command line.
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 |
# File 'lib/tupelo/app/remote.rb', line 27 def remote client_class = Client, client_lib: 'tupelo/client', host: nil, **opts require 'easy-serve/remote' ## detach option so that remote process doesn't keep ssh connection snames = :seqd, :cseqd, :arcd if tunnel_default and not opts.key?(:tunnel) opts[:tunnel] = true end if opts[:eval] ez.remote *snames, host: host, **opts, eval: %{ require #{client_lib.inspect} seqd, cseqd, arcd = *conns client_class = Object.const_get(#{client_class.name.inspect}) begin log.progname = "client <starting in \#{log.progname}>" client = client_class.new( seq: seqd, cseq: cseqd, arc: arcd, log: log) client.start do log.progname = "client \#{client.client_id}" end client.instance_eval #{opts[:eval].inspect} ensure client.stop if client end } elsif block_given? block = Proc.new ez.remote *snames, host: host, **opts do |seqd, cseqd, arcd| run_client client_class, seq: seqd, cseq: cseqd, arc: arcd, log: log do |client| if block.arity == 0 client.instance_eval &block else yield client end end end else raise ArgumentError, "cannot select remote mode based on arguments" end end |
#run_client(client_class, opts) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/tupelo/app/builder.rb', line 88 def run_client client_class, opts log = opts[:log] log.progname = "client <starting in #{log.progname}>" client = client_class.new opts client.start do log.progname = "client #{client.client_id}" end yield client ensure client.stop if client # gracefully exit the tuplespace management thread end |
#start_trace ⇒ Object
49 50 51 52 53 54 55 56 57 |
# File 'lib/tupelo/app/trace.rb', line 49 def start_trace child passive: true do trap :INT do exit! end trace_loop end end |