climax 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +117 -7
- data/lib/climax/application.rb +2 -0
- data/lib/climax/control_drb.rb +6 -3
- data/lib/climax/version.rb +1 -1
- metadata +2 -2
data/README.markdown
CHANGED
@@ -108,10 +108,12 @@ The above example is a simple application that adds an extra command line option
|
|
108
108
|
`configure` method. The `pre_main` method is simple and just writes a debug log statement. As you
|
109
109
|
can see logging has been setup at this point. Then the `main` method is called. Because the `main`
|
110
110
|
method in this example always returns nil, this application will run forever until it is stopped
|
111
|
-
externally (`Ctrl-C`, `kill
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
externally (`Ctrl-C`, `kill`, or using the Control DRb). Using `Ctrl-C` and `kill -INT` (i.e.,
|
112
|
+
sending an Interrupt signal) will cause the application to exit gracefully. The current iteration of
|
113
|
+
`main` will finish and then `post_main` will be run. You can send another Interrupt signal, for
|
114
|
+
example by hitting `Ctrl-C` twice, to exit the application immediately. Likewise if the Control DRb
|
115
|
+
is used then the application will exit in an orderly fashion and the `post_main` method will be
|
116
|
+
called. Notice that for free you can fork this application, change the log level with the
|
115
117
|
`--log-level` option, write the logs to a file using the `--log-file` option, and you can start a
|
116
118
|
debugger at any time while this application is running using the Control DRb. The Control DRb has a
|
117
119
|
lot of power. We'll talk about it more below.
|
@@ -159,12 +161,19 @@ good idea to keep each iteration of `main` as short as possible, although this i
|
|
159
161
|
requirement. In other words, if you wish to enter the remote debugger for a running process, the
|
160
162
|
debugger will not begin until the current iteration of `main` has completed.
|
161
163
|
|
164
|
+
This is exactly how graceful exiting is accomplished with climax. When you send an Interrupt signal
|
165
|
+
(via `Ctrl-C` or by sending a `kill -INT` to your application), climax intercepts this signal and
|
166
|
+
places a `:exit` event onto the event queue. If climax intercepts a second Interrupt signal it will
|
167
|
+
halt execution immediately.
|
168
|
+
|
162
169
|
This is excellent for stopping a long running process without interrupting its work. By sending an
|
163
|
-
:exit or :quit event, whether through the Control DRb or
|
164
|
-
application will be allowed to finish processing its current unit of
|
170
|
+
:exit or :quit event, whether through the Control DRb, or by sending an Interrupt signal, or from
|
171
|
+
your application itself, your application will be allowed to finish processing its current unit of
|
172
|
+
work before exiting.
|
165
173
|
|
166
174
|
For your convenience there is also a 'climax_has_event?' method that returns true only if there are
|
167
|
-
events waiting on the event queue.
|
175
|
+
events waiting on the event queue. Your application can use this to determine if `main` should give
|
176
|
+
up control temporarily to allow climax to handle events on the queue.
|
168
177
|
|
169
178
|
Generating a New Application
|
170
179
|
============================
|
@@ -237,3 +246,104 @@ and then execute:
|
|
237
246
|
climax control start_debugger
|
238
247
|
|
239
248
|
When you are finished type `quit` to exit the debugger and resume your application.
|
249
|
+
|
250
|
+
Extending the Control DRb with Custom Functionality
|
251
|
+
---------------------------------------------------
|
252
|
+
|
253
|
+
Extending the Control DRb is a key aspect of climax. For instance it is a common idiom for web
|
254
|
+
applications to delegate difficult tasks to background jobs. Let's take a common scenario and see
|
255
|
+
how we might implement this scenario with climax.
|
256
|
+
|
257
|
+
In this example there is a web application that allows users to upload images. The image is stored
|
258
|
+
in a temporary directory by the web application and then a request is sent to a background job
|
259
|
+
asking it to process the image and store it in a more permanent location. Let's say the web
|
260
|
+
application simply wants to send the command `process_image` and pass as an argument the path of the
|
261
|
+
image that was uploaded.
|
262
|
+
|
263
|
+
Let's see how we can extend the Control DRb with a `process_image` method. We'll also see a possible
|
264
|
+
workflow for how the background job might tackle its work.
|
265
|
+
|
266
|
+
require 'climax'
|
267
|
+
require 'fileutils'
|
268
|
+
|
269
|
+
module Climax
|
270
|
+
class ControlServer
|
271
|
+
def process_image (path)
|
272
|
+
app.climax_send_event(:process_image, path)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class ImageProcessor
|
278
|
+
include Climax::Application
|
279
|
+
|
280
|
+
def configure
|
281
|
+
options do
|
282
|
+
on 't', 'target-directory=', 'Destination directory to save processed images to.', :default => '/var/saved/images'
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def pre_main
|
287
|
+
FileUtils.mkdir_p(opts[:'target-directory'])
|
288
|
+
@processor_queue = []
|
289
|
+
end
|
290
|
+
|
291
|
+
def main
|
292
|
+
if @processor_queue.empty?
|
293
|
+
sleep 0.5
|
294
|
+
return nil
|
295
|
+
end
|
296
|
+
|
297
|
+
image_path = @processor_queue.pop
|
298
|
+
log.info "Processing image #{image_path}"
|
299
|
+
do_work(image_path)
|
300
|
+
return nil
|
301
|
+
end
|
302
|
+
|
303
|
+
def process_image (path)
|
304
|
+
@processor_queue.push(path)
|
305
|
+
end
|
306
|
+
|
307
|
+
def do_work(path)
|
308
|
+
# process image at path
|
309
|
+
# save to target directory
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
Adding your own commands to the Control DRb couldn't be easier. Simply extend the
|
314
|
+
`Climax::ControlServer` class with your own methods that push events onto the climax event queue.
|
315
|
+
When climax processes the event it will call a method in your application instance with the same
|
316
|
+
name as the event. In the example above we send a `:process_image` event with an argument. When
|
317
|
+
climax processes this event it will attempt to call a `process_image` method in the application
|
318
|
+
instance, passing along any arguments.
|
319
|
+
|
320
|
+
In this case we simply add the work to a simple queue and allow `main` to process the jobs from the
|
321
|
+
queue.
|
322
|
+
|
323
|
+
Notice that when you are extending `Climax::ControlServer` you have access to your application
|
324
|
+
instance via the `app` method. From here you can call any publicly available methods on your
|
325
|
+
application instance. *But be careful*. The DRb is running in a separate thread. This is why we
|
326
|
+
simply send events! It is always best to only send events from your custom ControlServer methods.
|
327
|
+
Doing so allows you to never need worry about making your application thread-safe. If you're a
|
328
|
+
cowboy and decide to call various public methods on your app instance directly from your custom
|
329
|
+
`ControlServer` methods you may end up with some strange results. So unless you are familiar with
|
330
|
+
thread-safe applications it is suggested that you only place events onto the queue from your custom
|
331
|
+
`ControlServer` methods.
|
332
|
+
|
333
|
+
Now the web application can simply connect to your application's DRb and call the `process_image`
|
334
|
+
method, passing it an image path.
|
335
|
+
|
336
|
+
Something interesting about this is that non-ruby applications can also easily tell our image
|
337
|
+
processor to process images.
|
338
|
+
|
339
|
+
For instance you can send commands to your application using the `climax` CLI interface:
|
340
|
+
|
341
|
+
climax control process_image /tmp/uploaded-images/tmp-d8ej2.jpg
|
342
|
+
|
343
|
+
This means any application, even just simple shell scripts, can easily send commands to our
|
344
|
+
background job.
|
345
|
+
|
346
|
+
Of course it is best to give each of your climax applications a unique Control DRb port. You can
|
347
|
+
then specify which port to send commands to with the `-p` option to `climax control`:
|
348
|
+
|
349
|
+
climax control -p $IMAGE_PROCESSOR_PORT process_image /tmp/uploaded-images/tmp-d8ej2.jpg
|
data/lib/climax/application.rb
CHANGED
@@ -172,6 +172,8 @@ module Climax
|
|
172
172
|
when :stop_control_drb then DRb.stop_service
|
173
173
|
when :start_remote_debugger then binding.remote_pry rescue nil
|
174
174
|
when :quit, :exit then return 0
|
175
|
+
else
|
176
|
+
self.send(event.type, *[event.payload])
|
175
177
|
end
|
176
178
|
end
|
177
179
|
end while !event.nil?
|
data/lib/climax/control_drb.rb
CHANGED
@@ -2,20 +2,23 @@ require 'drb/drb'
|
|
2
2
|
|
3
3
|
module Climax
|
4
4
|
class ControlServer
|
5
|
+
|
5
6
|
def initialize(app)
|
6
7
|
@app = app
|
7
8
|
end
|
8
9
|
|
10
|
+
attr_reader :app
|
11
|
+
|
9
12
|
def log_level
|
10
|
-
|
13
|
+
app.log_level
|
11
14
|
end
|
12
15
|
|
13
16
|
def log_level= (level)
|
14
|
-
|
17
|
+
app.climax_send_event(:set_log_level, level)
|
15
18
|
end
|
16
19
|
|
17
20
|
def start_debugger
|
18
|
-
|
21
|
+
app.climax_send_event(:start_remote_debugger)
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
data/lib/climax/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: climax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pry
|