Skip to content

Respondent Event Broadcaster

The Respondent Event Broadcaster is a fire-and-forget real-time stream of respondent events that occur in REX. Subscribers authenticate to the stream using REX’s standard signing methodology, and will immediately start receiving events as they happen. The stream is not durable in any way, so events that occur while not subscribed will not be queued or delivered. Events that are not delivered due to channel backpressure or network errors will not be retried.

The event broadcasting stream is implemented as a long-running gRPC server-side stream, hosted at events.rex.dynata.com. There are a number of languages with ready-made libraries available that can generate the bulk of the client used to connect to the stream. The stream uses TLS but does not require client-side cryptographic authentication.

Once you have generated the event stream client in your preferred language, calling the gRPC endpoint is fairly simple.

  1. Construct a secure channel using the event stream’s hostname, omitting any client certificate options.
  2. Use that channel to construct the generated event stream client.
  3. Generate the request signature.
  4. Call the Listen endpoint on the client with the request signature, access key, and expiration.
# The official Python gRPC library
import grpc
# These two modules are generated via the grpcio-tools package
import event_stream_pb2
import event_stream_pb2_grpc
def run():
# The service uses TLS, but does not require client-side certificate configuration.
credentials = grpc.ssl_channel_credentials(root_certificates=None, private_key=None, certificate_chain=None)
with grpc.secure_channel(
# The format of the URI will vary depending on your language of choice.
# Here we need to specify host but not the protocol or port.
'events.rex.dynata.com',
credentials,
# Ensure that the channel uses client-side keepalives.
options=(('grpc.keepalive_time_ms', 1000),)
) as channel:
client = event_stream_pb2_grpc.EventStreamStub(channel)
# Signature creation steps have been omitted. See Authentication for details.
events = client.Listen(event_stream_pb2.Auth(expiration=expiration, access_key=access_key, signature=signature))
for event in events:
# Do some exciting things with the data.
# Here we're simply printing a human-readable version of the structure to stdout.
print(f"{repr(event)}")
if __name__ == '__main__':
run()

Use the standard Dynata signing methodology with "respondent.events" as the signing string to create the signature

Complete signing details and code examples*.

Request payload requires:

  1. The access key used to create the signature
  2. The expiration used to create the signature
  3. The signature

The event stream’s gRPC service is defined as follows:

syntax = "proto3";
package eventstream;
service EventStream {
rpc Listen(Auth) returns (stream Event) {}
}
message Auth {
string expiration = 1;
string access_key = 2;
string signature = 3;
}
message Event {
message Start {
int64 group_id = 1;
}
message End {
string disposition = 1;
string status = 2;
}
string session = 1;
oneof data {
Start start = 2;
End end = 3;
}
string timestamp = 4;
}

As described in the previous section, the event stream is expecting the initiating request to be a REX signature payload. The responses that come down the stream are individual Events that come in a couple different sub-types.

Each Event will have a session token and timestamp associated with it. The event will also have a data field, which is one of two types. A Start will have the group id associated with opportunities in the Registry, and an End will have the respondent’s final disposition. The disposition information will be the same as exposed by the respondent gateway.

As an example, grpcio-tools will use that protobuf definition to generate Python classes that look something like:

class Event:
def __init__(self, session: str, data, timestamp: str):
self.session = session
self.data = data
self.timestamp = timestamp
class Start:
def __init__(self, group_id: int):
self.group_id = group_id
class End:
def __init__(self, disposition: str, status: str):
self.disposition = disposition
self.status = status

There may be periods of low activity on the stream. In order to prevent your local client from closing the connection preemptively, we recommend using client-side keepalives. Most libraries have an option to enable client-side HTTP2 or even TCP level keepalive pings.

Although we strive to have an uninterrupted service, there are situations in which your streaming connection may be severed. We recommend immediately re-authenticating with the service upon disconnect to minimize the number of missed messages.