The execution engine¶
AsyncSocketFactory¶
The AsyncSocketFactory
is an entry point to the Async Socket Library. The factory is used to create sockets
and request executors. You can use direct instantiation for this object:
1 2 3 | use AsyncSockets\Socket\AsyncSocketFactory;
$factory = new AsyncSocketFactory();
|
Factory can be configured using Configuration
object. The above code is the shortcut for configuring factory with
default values:
1 2 3 4 5 6 7 8 9 10 11 12 | use AsyncSockets\Socket\AsyncSocketFactory;
use AsyncSockets\Configuration\Configuration;
$configuration = new Configuration(
[
'connectTimeout' => ini_get('default_socket_timeout'),
'ioTimeout' => ini_get('default_socket_timeout'),
'preferredEngines' => ['libevent', 'native'],
]
);
$factory = new AsyncSocketFactory($configuration);
|
Note
To see all configuration options see Options reference
Request executor¶
Request executor is a primary execution engine for all socket requests. Each time you need to run a request,
you will use Request executor. Request executors are defined by RequestExecutorInterface
which allows to customize operations processing. There are two different implementations out of the box:
native and libevent. The former is the pure php handler, the latter is based on libevent php library.
You can receive an instance of RequestExecutorInterface
using the factory:
1 2 3 4 use AsyncSockets\Socket\AsyncSocketFactory; $factory = new AsyncSocketFactory(); $executor = $factory->createRequestExecutor();
The purposes of Request Executor are:
- Providing a bag for adding sockets (See Setting up a socket section below);
- Dispatching events during sockets’ lifecycle;
- Executing request.
A request executor can be set up with global event handler, which will be applied to each added socket, and with limitation solver - an object restricting amount of executing requests at time.
Global event handler is the implementation of EventHandlerInterface
, which will be called for every event on every
added socket. There are four implementations of this interface out of the box:
CallbackEventHandler
takes array of callable, indexed by event type. For certain event type a certain callable will be invoked. Several callbacks can be defined for one event type;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $handler = new CallbackEventHandler( [ EventType::INITIALIZE => [$this, 'logEvent'], EventType::WRITE => [ [$this, 'logEvent'], [$this, 'onWrite'] ], EventType::READ => [ [$this, 'logEvent'], [$this, 'onRead'] ], EventType::EXCEPTION => [$this, 'onException'], EventType::TIMEOUT => [ [$this, 'onTimeout'], function () { echo "Timeout occured!\n"; } ], ] );
EventHandlerFromSymfonyEventDispatcher
dispatches all socket event to symfony EventDispatcher;
EventMultiHandler
is the composite forEventHandlerInterface
implementations;
RemoveFinishedSocketsEventHandler
decorator for any implementation ofEventHandlerInterface
which automatically removes completed sockets fromRequestExecutor
. Recommended to use for accepted clients from server sockets.
The limitation solver is the component restricting amount of executed at once requests. Out of the box two strategies are available:
NoLimitationSolver
doesn’t restrict anything, it is a default one;ConstantLimitationSolver
restricts amount of running requests to given number.
Note
You can write custom limitation solver, see Custom limitation solver
To set up event handler or limitation solver use the following code:
1 2 3 4 5 6 7 8 9 10 11 | $executor->withEventHandler(
new CallbackEventHandler(
[
EventType::INITIALIZE => [$this, 'onInitialize'],
EventType::WRITE => [$this, 'onWrite'],
....
]
)
);
$executor->withLimitationSolver(new ConstantLimitationSolver(20));
|
Socket lifecycle¶
During request socket pass through lifecycle shown in the figure below.
Each state except added and removed calls event handler with some information about occurred event.
Setting up a socket¶
Socket can be added into execution engine using socketBag()
method from RequestExecutorInterface
. It returns
object of class SocketBagInterface
allows to manage sockets. Socket bag is a container for all sockets processed
by the engine. Every socket can have it’s own event handler and options.
You can use the following code to add socket into RequestExecutor:
1 2 3 4 5 6 7 8 9 10 | $executor->socketBag()->addSocket(
$socket,
new WriteOperation('some data'),
[
RequestExecutorInterface::META_ADDRESS => 'tls://example.com:443',
RequestExecutorInterface::META_CONNECTION_TIMEOUT => 30,
RequestExecutorInterface::META_IO_TIMEOUT => 5,
],
$handler
);
|
Method addSocket()
accepts four arguments: socket, operation, metadata and event handler.
Socket is the object, created by AsyncSocketFactory
or received by AcceptEvent.
Metadata is a key-value array with settings for this socket.
Event handler is an implementation of EventHandlerInterface
, which will be invoked only for this socket.
Once you set up all sockets, you can execute the request:
1 | $executor->executeRequest();
|
Warning
You should not create nested RequestExecutor during request processing.