Relay.Consumer
A Relay Consumer is a simple PHP class that runs in its own process along side your application to handle calling and messaging events in realtime. Relay Consumers abstract all the setup of connecting to Relay and automatically dispatch workers to handle requests. Consumers will receive requests and delegate them to their own worker thread, allowing you to focus on your business logic without having to worry about multi-threading or blocking, everything just works. Think of Relay Consumers like a background worker system for all your calling and messaging needs.
Creating Consumers
A Relay Consumer is a simple object, customized by specifying contexts and event handlers to respond to incoming events.
A consumer has 2 required properties: project
, token
, and usually requires at least one contexts
for incoming events. Project and Token are used to authenticate your Consumer to your SignalWire account. Contexts are a list of contexts you want this Consumer to listen for. Learn more about Contexts.
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function onIncomingCall($call): Coroutine {
yield $call->answer();
yield $call->playTTS(['text' => 'Welcome to SignalWire!']);
}
}
$consumer = new CustomConsumer();
$consumer->run();
Coroutine & yield keywords
In the Consumer examples you can see the special keyword yield
and the return type Coroutine
on the onIncomingCall
method. These keywords help you write asynchronous code that "seems" synchronous, avoiding the need to nest your code in multiple callbacks.
Since the Relay PHP SDK is built on top of ReactPHP, a lot of methods return Promises that will be resolved with the result of the asynchronous operations. By flattening out the nested callbacks, you can just yield
the Promises to wait for its value.
If you are familiar with Javascript, yield
is similar to the async/await
syntax in JS.
<?php
public function onIncomingCall($call): Coroutine {
// Without using yield
$call->answer()->done(function($answerResult) {
// .. use $answerResult here..
});
// Using yield
$answerResult = yield $call->answer();
}
Note: within functions with return type Coroutine
you must force PHP to parse the function as a Generator so, if you don't need any yield
in your code, just set the first line as:
<?php
public function onIncomingCall($call): Coroutine {
yield;
// ...
}
Initializing Consumers
You can optionally add an setup
method if you need to do any initialization work before processing messages. This is useful to do any one-off work that you wouldn't want to do for each and every event, such as setting up logging or connecting to a datastore.
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function setup() {
// Initialize anything you'd like available for all events.
// Like logging, database connections, etc.
}
public function onIncomingCall($call): Coroutine {
yield $call->answer();
yield $call->playTTS(['text' => 'Welcome to SignalWire!']);
}
}
$consumer = new CustomConsumer();
$consumer->run();
Properties
client | Relay.Client | The underlying Relay client object. |
Event Handlers
Event handlers are where you will write most of your code. They are executed when your consumer receives a matching event for the contexts specified by your Consumer.
ready
Executed once your Consumer is connected to Relay and the session has been established.
Available In:
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function ready(): Coroutine {
$params = [ 'type' => 'phone', 'from' => '+1XXXXXXXXXX', 'to' => '+1YYYYYYYYYY' ];
$dialResult = yield $this->client->calling->dial($params);
if ($dialResult->isSuccessful()) {
// Your active $call..
$call = $dialResult->getCall();
}
}
}
$consumer = new CustomConsumer();
$consumer->run();
onIncomingCall
Executed when you receive an inbound call, passes in the inbound Call
object.
Available In:
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function onIncomingCall($call): Coroutine {
yield $call->answer();
yield $call->playTTS(['text' => 'Welcome to SignalWire!']);
}
}
$consumer = new CustomConsumer();
$consumer->run();
onTask
Executed with your message sent through a Relay.Task
.
Available In:
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function onTask($message): Coroutine {
yield;
print_r($message);
// ..Use your own $message sent in the context "default" from a Relay.Task
}
}
$consumer = new CustomConsumer();
$consumer->run();
onIncomingMessage
Executed when you receive an inbound SMS or MMS, passes in the inbound Message
object.
This method is a Coroutine to simplify writing of asynchronous code in here.
Available In:
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function onIncomingMessage($message): Coroutine {
yield;
// Handle the inbound message here..
}
}
$consumer = new CustomConsumer();
$consumer->run();
onMessageStateChange
Executed when a message state changes, passes in the inbound Message
object.
This method is a Coroutine to simplify writing of asynchronous code in here.
Available In:
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
use SignalWire\Log;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function ready(): Coroutine {
$params = [
'context' => 'default',
'from' => '+1xxx',
'to' => '+1yyy',
'body' => 'Welcome at SignalWire!'
];
$result = yield $this->client->messaging->send($params);
if ($result->isSuccessful()) {
Log::info('SMS queued successfully!');
}
}
public function onMessageStateChange($message): Coroutine {
yield;
// Keep track of your SMS state changes..
Log::info("Message {$message->id} state: {$message->state}.");
}
}
$consumer = new CustomConsumer();
$consumer->run();
Cleaning Up on Exit
When a Relay Consumer shuts down, you have the opportunity to clean up any resources held by the consumer. For example, you could close any open files, network connections, or send a notification to your monitoring service.
Just implement a teardown
method in your consumer and it will be called during the shutdown procedure.
<?php
require dirname(__FILE__) . '/vendor/autoload.php';
use Generator as Coroutine;
class CustomConsumer extends SignalWire\Relay\Consumer {
public $project = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
public $token = 'PTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
public $contexts = ['default'];
public function onIncomingCall($call): Coroutine {
yield $call->answer();
yield $call->playTTS(['text' => 'Welcome to SignalWire!']);
}
public function teardown(): Coroutine {
// Clean up any resources when exiting.
}
}
$consumer = new CustomConsumer();
$consumer->run();
Running Consumers
Running a consumer is just like running any other PHP script, simply execute the script as a separate process and ensure you invoke the ->run();
method at the end of your script. The process will stay up until you shut it down.
Shutting Down Consumers
In order to gracefully shut down a Relay consumer process, send it the SIGTERM
signal. Most process supervisors such as Runit, Docker and Kubernetes send this signal when shutting down a process, so using those systems will make things easier.