NAME
Net::Async::Beanstalk - Non-blocking beanstalk client
SYNOPSIS
use IO::Async::Loop;
use Net::Async::Beanstalk;
my $loop = IO::Async::Loop->new();
my $client = Net::Async::Beanstalk->new();
$loop->add($client);
$client->connect(host => 'localhost', service => '11300')->get();
$client->put("anything")->get();
$loop->run();
BUGS
Receiving on_disconnect after sending quit might not work.
In fact disconnecting hasn't been tested at all, even ad-hoc.
This document is even longer.
There are no tests
See if it's appropriate to steal the tests out of Beanstalk::Client.
DESCRIPTION
Implements the client-side of the beanstalk 1.10 protocol described in https://raw.githubusercontent.com/kr/beanstalkd/v1.10/doc/protocol.txt using IO::Async to provide an asynchronous non-blocking API.
Net::Async::Beanstalk is based on Moo and IO::Async::Stream. Refer to those modules' documentation for basic usage. In particular "connect" in IO::Async::Loop.
ATTRIBUTES
Includes the command stack from Net::Async::Beanstalk::Send.
- default_priority (10,000)
- defauly_delay (0)
- default_ttr (120)
-
Default values to associate with a job when it is "put" on the beanstalk server. The defaults here are arbitrary; they have been chosen to match the default values from AnyEvent::Beanstalk.
- decoder (&YAML::Load)
- encoder (&YAML::Dump)
-
A coderef which will be used to deserialise or serialise jobs as they are retreived from or sent to a beanstalk server.
This is not related to how the result of
listorstatscommands are deserialised. This is always done using "Load" in YAML. - using
-
The name of the tube which was recently used.
- _watching
-
A hashref who's keys are the tubes which are being
watched. The values are ignored.Use the accessor
watchingto get the list ofwatched tubes instead of using the attribute directly.
CLASS
A Net::Async::Beanstalk object represents a single connection to a beanstalkd server. Once a connection has been established (see "CONNECTING") commands may be submitted by calling the objects methods (see "COMMAND METHODS").
The command methods all return a Future which will either be completed (marked done) with the result if the command was a success or failed with the error.
The command methods are named after the beanstalk API command that they implement, with the hyphens changed to an underscore (s/-/_/g). All command methods but "put" take the same options in the same order as the respective API command. "reserve" also has an option added to it so that it can be used to make reservations with or without a timeout.
Some events may happen without a command having been sent or in spite of a command being actively executed. These invoke the events documented below and do not complete or fail the associated Future. See the documentation of each error (there aren't many) for the details in "ERRORS".
Although this class implements a non-blocking beanstalk client, the protocol itself is not asynchronous. Each command sent will receive a response before the next command will be processed although in practice network buffering makes it appear that commands can be sent while waiting for a previous command's response.
Ordinarily this is irrelevant as all the commands except reserve and reserve-with-timeout respond quickly enough that any delay will be negligible and this class' internal command stack smooths over the times where that's not the case.
When any command which blocks the server has been sent, other commands will be stacked up waiting to be sent to the server but will not be handled (that is, not even put on the wire) until the running command command has completed (perhaps with a timeout).
If this is a concern, the beanstalkd server is explicitly written to support multiple connections with low overhead, so there is no need to perform all operations using the same client object. Just be aware that the list of active tubes is not copied (by default) from one client to another. Each client starts off using and watching the default tube.
When a job has been reserved by a client (which remains connected) that job is invisible to any other clients. It cannot, for example, be deleted except over the same connected in which it was reserved and if that connection is closed the job will return to the ready queue and may be reserved by another client.
CONNECTING
Voodoo.
ERRORS
There are not many error conditions described by the beanstalk protocol. Net::Async::Beanstalk::Receive also defines errors in the event of bugs revealing mistakes in this code or communication failures. Each will cause either the current Future to fail, raise an event, or both.
See each error's description but by and large the errors that happen because a command failed (which is not the same thing thing as "while a command was active") fail the Future while the error conditions that arise spontaneously invoke an on_error event (defined in IO::Async::Notifier). If the Net::Async::Beanstalk object (or its parent) is created without an on_error handler then the default on_error handler will be used which calls die.
Except where noted each error or failure includes the arguments which were sent with the command to the server (not including the command itself). If you call a command such as this
my $give_it_a_rest = $beanstalk->bury(0x6642, 9_001);
then $give_it_a_rest will hold a Future which will eventually fail and call its handler with:
$h->("...buried: 26180 not found", "beanstalk-peek", 0x6632, 9_001);
The exceptional errors are:
Protocol error: Bad format-
Category:
beanstalk-internalArguments: The buffer which was written into the communication stream.
This error invokes an
on_errorevent and fails the active Future.The server received a command line that was not well-formed. This should never happen and when it does it indicates an error in this module. Please report it so that it can be repaired.
Protocol error: Internal error-
Category:
beanstalk-serverArguments: Everything.
This error invokes
on_erroronly.The server suffered from an internal error. This should never happen and when it does it indicates an error in the server. Please report it to the beanstalk maintainer so that it can be repaired.
This error does not attempt to fail the current or any pending Futures, however the server's probably about to crash so your code should deal with that and the pending Futures gracefully.
Protocol error: Out of memory-
Category:
beanstalk-serverArguments: The command name and then the arguments as usual.
This error only fails the active Future.
The server ran out of memory. This happens sometimes but generally it should not. Please report it to your system administrator so that he can be repaired.
Protocol error: Unknown command-
Category:
beanstalk-internalArguments: The command name and then the arguments as usual.
This error invokes an
on_errorevent and fails the active Future.This module sent a command the server did not understand. This should never happen and when it does it indicates an error in the server or a protocol mismatch between the server and client.
Protocol error: Unknown response-
Category:
beanstalk-serverArguments: The buffer which was received from the communication stream as an arrayref of each received chunk.
This error invokes
on_erroronly.The server sent a message this client did not understand. This should never happen and when it does it indicates an error in the server or a protocol mismatch between the server and client.
This error does not attempt to fail the current or any pending Futures, however the server's speaking gibberish so nobody knows what's going to happen next. Your code should deal with that and the pending Futures gracefully.
In order to make the command stack work, each Future is created with an on_ready handler which sends the next pending command. In the event of an error the pending commands may become invalid. This class makes no attempt to deal with that.
One other protocol error (Expected cr+lf) can be received only in response to a "put" command (it does not invoke an on_error event).
COMMAND METHODS
Methods which initiate a command on the server are implemented in Net::Async::Beanstalk::Send. The server response is processed by the event handlers in Net::Async::Beanstalk::Receive. Every command method returns a Future which will complete with the server's response to that command, whether success or failure.
With few exceptions, documented below, each method expects exactly the arguments that the respective command requires. The commands which expect to receive a YAML structure as the response (primarily the list-* commands) deserialise the response before returning it as a (non-reference) list or hash.
The methods are named with a _ where the API command has a -.
See the protocol documentation for further details on each command. They are:
- put ($job, %options) or put (%options)
-
Put a job onto the currently
used tube. The job data can be passed as the method's first argument or in%options.The job's
priority,delayorttrcan be set by including those values in%options. If they are not then the object's default value is used (see above).The job may be passed as the method's first or only argument or as
datain%options. It will be serialised using "encoder" if it's a reference and does not overload the stringify ("") operator.The job may instead be passed as
raw_datain%optionsif it has already been serialised.Regardless of whether
/encoderis used to serialise the job it is changed to a string of bytes using utf8::encode.It is an error to pass the job data in more than one form or to included unknown options and
putwill croak.Possible failures:
Protocol error: Expected cr+lf-
Category:
beanstalk-putArguments: As with
bad format, this should but does not include the buffer which was sent.This error only fails the active Future.
The client sent badly-formed job data which was not terminated by a CR+LF pair. This should never happen and when it does it indicates an error in this module. Please report it so that it can be repaired.
Invalid job: too big-
Category:
beanstalk-putThe client sent job data which was rejected by the server for being too large. The job has not beed stored in any queue.
Job was inserted but buried (out of memory): ID $id-
Category:
beanstalk-putThe job was successfully received by the server but it was unable to allocate memory to put it into the ready queue and so the job has been buried.
Job was not inserted: Server is draining-
Category:
beanstalk-putThe server is currently being drained and is not accepting new jobs. The job has not been stored in any queue.
- reserve (%options)
-
Reserve the next available job.
timeoutmay be passed in%optionsin which case thereserve-with-timoutcommand is sent instead.timeoutmay be0.The data returned by the server is transformed into a string of characters with "decode" in utf8 then deserialised using
/decoder.If the
asisoption is set to a true value then the data returned by the server is transformed into characters but is not deserialised.If the
rawoption is set to a true value then the data is left completely untouched.Possible failures:
- reserve_with_timeout ($time, %options)
-
Implemented by calling "reserve" with a
timeoutoption.$timemay be 0 which will cause the Future to fail immediately with aTimed outerror if there are no jobs available.Possible failures:
No job was reserved: Timed out-
Category:
beanstalk-reserveThe number of seconds specified in the timeout value to
reserve-with-timeouthas expired without a job becoming ready to reserve.
In addition all the failures possible in response to the "reserve" command can be received in response to
reserve_with_timeout. - bury ($job_id)
-
Possible failures:
- delete ($job_id)
-
Possible failures:
- ignore ($tube_name)
-
Possible failures:
- kick_job ($job_id)
-
Possible failures:
- kick ($max)
-
This command should not fail.
- list_tubes ()
-
This command should not fail.
- list_tubes_watched ()
-
This command should not fail.
- list_tube_used ()
-
This command should not fail.
- pause_tube ($tube_name, $delay)
-
Possible failures:
- peek ($job_id)
-
Possible failures:
- peek_buried ()
-
Possible failures:
- peek_delayed ()
-
Possible failures:
- peek_ready ()
-
Possible failures:
- quit ()
-
In theory this will raise an
on_disconnectin addition to completing the Future it returns. In practice I haven't written it yet. - release ($job_id, $priority, $delay)
-
Possible failures:
The job could not be released: $id not found-
Category:
beanstalk-jobThe job with ID
$idcould not be released because it does not exist or has not been previously reserved by this client. The job could not be released (out of memory): ID $id-
Category:
beanstalk-jobThe job with ID
$idcould not be released because the server ran out of memory.
- stats ()
-
This command should not fail.
- stats_job ($job_id)
-
Possible failures:
- stats_tube ($tube_name)
-
Possible failures:
- touch ($job_id)
-
Possible failures:
- use ($tube_name)
-
This command should not fail.
- watch ($tube_name)
-
This command should not fail.
OTHER METHODS
- reserve_pending () => @commands
-
Returns a all the entries in the command stack which refer to a
reserveorreserve-with-timeoutcommand. - disconnect () => $future
-
An alias for quit.
- sync () => $future
-
Returns a Future which completes when all pending commands have been responded to.
- watch_only (@tubes) => $future
-
Send a
list-tubes-watchedcommand and based on its result send a series ofwatchand thenignorecommands so that the tubes being watched for this client exactly matches@tubes.
INTERNAL METHODS
- _assert_state($response_word) => VOID
-
Raises an exception of the word received from the server is not something expected in response to the command which has most recently been sent.
- fail_command($message, $exception, @args) => $future
-
Remove the current command from the command stack and fail its Future with this method's arguments.
The Future returned is the one which returned when initiating a command and can be safely ignored.
This is used by Net::Async::Beanstalk::Receive when the client received an expected response which nevertheless indicates an error of some kind, such as
DEADLINE_SOONreceived in response to areservecommand. - finish_command($event, @args) => $future
-
Remove the current command from the command stack and complete its Future with this method's arguments.
The Future returned is the one which returned when initiating a command and can be safely ignored.
This is used by Net::Async::Beanstalk::Receive when the server sent a response to a command which indicates successful completion.
ALTERNATIVE IMPLEMENTATIONS
- AnyEvent::Beanstalk
-
A good module and asynchronous but it uses AnyEvent which ... the less said the better. The core of the protocol is implemented but it does not handle all error conditions. I have attempted to make Net::Async::Beanstalk's API superficially similar to this one.
- Beanstalk::Client
-
Also written by Graham Barr, this module seems to be slightly more functionally complete than its AnyEvent counterpart and has proven itself stable and fast but unfortunately does not operate asynchronously.
- AnyEvent::Beanstalk::Worker
-
Unfortunately also based on AnyEvent which is a shame because it implements what appears to be an interesting FSA using beanstalk queues.
- Queue::Beanstalk
-
Ancient, presumably unsupported and based on an out-dated version of the beanstalk protocol.
SEE ALSO
http://kr.github.com/beanstalkd/
https://raw.githubusercontent.com/kr/beanstalkd/v1.10/doc/protocol.txt
AUTHOR
Matthew King <chohag@jtan.com>