forked from earl/beanstalkc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TUTORIAL
352 lines (252 loc) · 9.54 KB
/
TUTORIAL
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
Welcome, dear stranger, to a tour de force through beanstalkd's capabilities.
Say hello to your fellow travel companion, the beanstalkc client library for
Python. You'll get to know each other fairly well during this trip, so better
start off on a friendly note. And now, let's go!
Getting Started
---------------
You'll need beanstalkd listening at port 14711 to follow along. So simply start
it using: `beanstalkd -l localhost -p 147111`
To use beanstalkc we have to import the library and set up a connection to an
(already running) beanstalkd server:
>>> import beanstalkc
>>> beanstalk = beanstalkc.Connection(host='localhost', port=14711)
If we leave out the `host` and/or `port` parameters, `'localhost'` and `11300`
would be used as defaults, respectively.
Basic Operation
---------------
Now that we have a connection set up, we can enqueue jobs:
>>> beanstalk.put('hey!')
1
Or we can request jobs:
>>> job = beanstalk.reserve()
>>> job.body
'hey!'
Once we are done with processing a job, we have to mark it as done, otherwise
jobs are re-queued by beanstalkd after a "time to run" (120 seconds, per
default) is surpassed. A job is marked as done, by calling `delete`:
>>> job.delete()
`reserve` blocks until a job is ready, possibly forever. If that is not desired,
we can invoke `reserve` with a timeout (in seconds) how long we want to wait to
receive a job. If such a `reserve` times out, it will return `None`:
>>> beanstalk.reserve(timeout=0) is None
True
If you use a timeout of 0, `reserve` will immediately return either a job or
`None`.
Tube Management
---------------
A single beanstalkd server can provide many different queues, called "tubes" in
beanstalkd. To see all available tubes:
>>> beanstalk.tubes()
['default']
A beanstalkd client can choose one tube into which its job are put. This is the
tube "used" by the client. To see what tube you are currently using:
>>> beanstalk.using()
'default'
Unless told otherwise, a client uses the 'default' tube. If you want to use a
different tube:
>>> beanstalk.use('foo')
'foo'
>>> beanstalk.using()
'foo'
If you decide to use a tube, that does not yet exist, the tube is automatically
created by beanstalkd:
>>> beanstalk.tubes()
['default', 'foo']
Of course, you can always switch back to the default tube. Tubes that don't have
any client using or watching, vanish automatically:
>>> beanstalk.use('default')
'default'
>>> beanstalk.using()
'default'
>>> beanstalk.tubes()
['default']
Further, a beanstalkd client can choose many tubes to reserve jobs from. These
tubes are "watched" by the client. To see what tubes you are currently watching:
>>> beanstalk.watching()
['default']
To watch an additional tube:
>>> beanstalk.watch('bar')
2
>>> beanstalk.watching()
['default', 'bar']
As before, tubes that do not yet exist are created automatically once you start
watching them:
>>> beanstalk.tubes()
['default', 'bar']
To stop watching a tube:
>>> beanstalk.ignore('bar')
1
>>> beanstalk.watching()
['default']
You can't watch zero tubes. So if you try to ignore the last tube you are
watching, this is silently ignored:
>>> beanstalk.ignore('default')
1
>>> beanstalk.watching()
['default']
Statistics
----------
Beanstalkd accumulates various statistics at the server, tube and job level.
Statistical details for a job can only be retrieved during the job's lifecycle.
So let's create another job:
>>> beanstalk.put('ho?')
2
>>> job = beanstalk.reserve()
Now we retrieve job-level statistics:
>>> from pprint import pprint
>>> pprint(job.stats())
{'age': 0,
...
'id': 2,
...
'state': 'reserved',
...
'tube': 'default'}
If you try to access job stats after the job was deleted, you'll get a
`CommandFailed` exception:
>>> job.delete()
>>> job.stats()
Traceback (most recent call last):
...
CommandFailed: ('stats-job', 'NOT_FOUND', [])
Let's have a look at some numbers for the `'default'` tube:
>>> pprint(beanstalk.stats_tube('default'))
{'current-jobs-buried': 0,
'current-jobs-delayed': 0,
'current-jobs-ready': 0,
'current-jobs-reserved': 0,
'current-jobs-urgent': 0,
'current-using': 1,
'current-waiting': 0,
'current-watching': 1,
'name': 'default',
'total-jobs': 2}
Finally, there's an abundant amount of server-level statistics accessible via
the `Connection`'s `stats` method. We won't go into details here, but:
>>> pprint(beanstalk.stats())
{...
'current-connections': 1,
'current-jobs-buried': 0,
'current-jobs-delayed': 0,
'current-jobs-ready': 0,
'current-jobs-reserved': 0,
'current-jobs-urgent': 0,
...}
Advanced Operation
------------------
In "Basic Operation" above, we discussed the typical lifecycle of a job:
put reserve delete
-----> [READY] ---------> [RESERVED] --------> *poof*
(This picture was taken from beanstalkd's protocol documentation. It is
originally contained in `protocol.txt`, part of the beanstalkd
distribution.) #doctest:+SKIP
But besides `ready` and `reserved`, a job can also be `delayed` or `buried`.
Along with those states come a few transitions, so the full picture looks liek
the following:
put with delay release with delay
----------------> [DELAYED] <------------.
| |
| (time passes) |
| |
put v reserve | delete
-----------------> [READY] ---------> [RESERVED] --------> *poof*
^ ^ | |
| \ release | |
| `-------------' |
| |
| kick |
| |
| bury |
[BURIED] <---------------'
|
| delete
`--------> *poof*
(This picture was taken from beanstalkd's protocol documentation. It is
originally contained in `protocol.txt`, part of the beanstalkd
distribution.) #doctest:+SKIP
Now let's have a practical look at those new possibilities. For a start, we can
create a job with a delay. Such a job will only be available for reservation
once this delay passes:
>>> beanstalk.put('yes!', delay=1)
3
>>> beanstalk.reserve(timeout=0) is None
True
>>> job = beanstalk.reserve(timeout=1)
>>> job.body
'yes!'
If we are not interested in a job anymore (e.g. after we failed to
process it), we can simply release the job back to the tube it came from:
>>> job.release()
>>> job.stats()['state']
'ready'
Want to get rid of a job? Well, just "bury" it! A buried job is put aside and is
therefore not available for reservation anymore:
>>> job = beanstalk.reserve()
>>> job.bury()
>>> job.stats()['state']
'buried'
>>> beanstalk.reserve(timeout=0) is None
True
Buried jobs are maintained in a special FIFO-queue outside of the normal job
processing lifecycle until they are kicked alive again:
>>> beanstalk.kick()
1
You can request many jobs to be kicked alive at once, `kick`'s return value will
tell you how many jobs were actually kicked alive again:
>>> beanstalk.kick(42)
0
Inspecting Jobs
---------------
Besides reserving jobs, a client can also "peek" at jobs. This allows to inspect
jobs without modifying their state. If you know the `id` of a job you're
interested, you can directly peek at the job. We still have job #3 hanging
around from our previous examples, so:
>>> job = beanstalk.peek(3)
>>> job.body
'yes!'
Note that this peek did *not* reserve the job:
>>> job.stats()['state']
'ready'
If you try to peek at a non-existing job, you'll simply see nothing:
>>> beanstalk.peek(42) is None
True
If you are not interested in a particular job, but want to see jobs according to
their state, beanstalkd also provides a few commands. To peek at the same job
that would be returned by `reserve` -- the next ready job -- use `peek-ready`:
>>> job = beanstalk.peek_ready()
>>> job.body
'yes!'
Note that you can't release, or bury a job that was not reserved by you. Those
requests on unreserved jobs are silently ignored:
>>> job.release()
>>> job.bury()
>>> job.stats()['state']
'ready'
You can, though, delete a job that was not reserved by you:
>>> job.delete()
>>> job.stats()
Traceback (most recent call last):
...
CommandFailed: ('stats-job', 'NOT_FOUND', [])
Finally, you can also peek into the special queues for jobs that are delayed:
>>> beanstalk.put('o tempores', delay=120)
4
>>> job = beanstalk.peek_delayed()
>>> job.stats()['state']
'delayed'
... or buried:
>>> beanstalk.put('o mores!')
5
>>> job = beanstalk.reserve()
>>> job.bury()
>>> job = beanstalk.peek_buried()
>>> job.stats()['state']
'buried'
Fin!
----
>>> beanstalk.close()
That's it, for now. We've left a few capabilities untouched (touch, time-to-run
and job priorities). But if you've really read through all of the above, send me
a message and tell me what you think of it. And then go get yourself a treat.
You certainly deserve it.
-- Andreas Bolka, 2008-11