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:
CallbackEventHandlertakes 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"; } ], ] );
EventHandlerFromSymfonyEventDispatcherdispatches all socket event to symfony EventDispatcher;
EventMultiHandleris the composite forEventHandlerInterfaceimplementations;
RemoveFinishedSocketsEventHandlerdecorator for any implementation ofEventHandlerInterfacewhich automatically removes completed sockets fromRequestExecutor. Recommended to use for accepted clients from server sockets.
Note
You can register several global event handlers using withEventHandler method of RequestExecutorInterface.
The limitation solver is the component restricting amount of executed at once requests. Out of the box two strategies are available:
NoLimitationSolverdoesn’t restrict anything, it is a default one;ConstantLimitationSolverrestricts 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.
Socket lifecycle¶
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.