Skip to main content

Publish Messages 📝

Sending server-side messages to subscribers on Hotsock channels is the most common way to enable real-time features in your applications. Hotsock allows you to publish messages from your backend by invoking a Lambda function or by making an authenticated HTTP request. Connected clients can also send client-initiated messages.

Publish with Lambda

tip

This is the recommended method for publishing events from your backend. If you have the AWS SDK available in your backend application or are able to add it as a dependency, take this route.

All AWS SDKs across all available languages can invoke a Lambda function securely, enforcing least-privilege access using IAM roles with temporary credentials that are refreshed automatically by your EC2 instance, ECS task, or Lambda function.

Using the language of your choice, invoke the function referenced in the PublishFunctionArn output to publish a message. Copy the Arn from the stack output to the function name argument in your invoke call (either the full Arn or just the function name are supported).

lambdaClient.Invoke(context.TODO(), &lambda.InvokeInput{
FunctionName: aws.String("Hotsock-PublishFunction-AAABBBCCCDDD"),
Payload: []byte(`{"channel": "my-channel", "event": "my-event", "data": "👋"}`),
})

View the full documentation in the API reference.

For more complete examples - package imports, configuring the Lambda client, etc., reference the documentation for your preferred SDK.

Permissions to invoke Lambda

In each language-specific example below, lambdaClient or lambda_client is assumed to be a client configured to run as an IAM role or user that has permission to invoke your installation's publish function. Copy your function Arn from your installation's PublishFunctionArn output - the permissions assigned to your IAM role or user should look something like this:

{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["lambda:InvokeFunction"],
"Effect": "Allow",
"Resource": [
"arn:aws:lambda:us-east-1:111111111111:function:Hotsock-PublishFunction-AAABBBCCCDDD"
]
}
]
}

Publish with HTTP URL

warning

There are some downsides to using this publish method. It is and will continue to be fully supported, but the Lambda approach is more secure.

  • The API keys that can be used for all requests are static and must be used by all of your backend clients. Whether your backend publishers store a copy of this key or request its current value from Parameter Store periodically, having a shared key poses a security risk if the key leaks.
  • Hotsock grabs the current API key values from Parameter Store during each Lambda cold-start. This adds some (though minimal) cold-start latency because of the inline call to another AWS service.
  • API keys can be used to publish messages from anywhere on the Internet by anyone who has a key. Not ideal from a usage auditing perspective and often tough to keep track of who has the key(s).
  • Rotating the key is a manual process that you need to remember to do periodically.

Access your API keys

A pair of API keys were created alongside your installation. Their values are available by following the URLs in HttpApiSecretKey1ConsoleUrl and HttpApiSecretKey2ConsoleUrl.

tip

You can use either key for HTTP-based message publishing. There are two keys to allow for key rotation without downtime - you can change the value of one while continuing to use the other.

Get your publish URL

Your HTTP URL is displayed in the PublishHttpApiUrl stack output of your installation.

Make a publish request

Using any HTTP client in your code, make a POST request to your publish URL with the Authentication header set to Bearer YOUR_API_KEY and a JSON body containing at least an event and channel to publish to. Refer to the message format guide below for other available fields.

Here's an example with curl.

curl -X "POST" "https://e4zdy87vg9byo4ugvldt3rmn440lflwe.lambda-url.us-east-1.on.aws/publish" \
-H 'Authorization: Bearer JAnzQFqRXsBgV0kKvd2DYhJMk77IhL8j9J2sLi5b' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"channel": "my-channel",
"event": "my-event"
}'

You can adapt this for use with any HTTP client library in any programming language.

Message format

The shape of a message is the same whether you're invoking Lambda directly or using the HTTP API. At a minimum all messages must contain a channel and an event. Additional supported attributes are listed below.

{
"channel": "my-channel",
"event": "my-event"
}

channel

String (required) - The name of the channel where this message will be published. This can be any string up to 128 characters, but must not contain any asterisk (*), number sign (#), comma (,), or whitespace/newline characters.

data

JSON (optional) - Up to 32KiB of custom data specific to your application. This can be anything that is valid JSON - object, array, string, number, boolean, or null. Binary data must be Base64-encoded to a string.

deduplicationId

String (optional) - If supplied as a non-empty string and if multiple messages with the same deduplicationId value are received within 5 minutes of each other, only the first message will be published. Additional copies will be dropped.

If you're publishing from a source that retries upon failure, set this to a value that is consistent across all attempts to publish that message. This ensures that if Hotsock receives the message but a networking issue prevents your application from receiving the success response, retry attempts will not publish duplicate messages.

warning

Providing a deduplicationId while also enabling eagerIdGeneration is not recommended. See below for details.

eagerIdGeneration

Boolean (optional) - If you need to store a backend copy of the message ID that is published to the channel for follow-up requests, set this to true. Default is false.

Enabling this can ever-so-slightly affect message ordering. When this is option is disabled, messages receive a monotonically increasing ID at the time they are processed, ensuring that messages are always processed and identifiable sequentially within a channel. When this option is enabled (true), messages receive an ID at publish time prior to being enqueued for processing, which is returned to the publisher. In scenarios where multiple messages are published within a few milliseconds, actual processing order is indeterminate.

warning

Enabling eagerIdGeneration while also providing a deduplicationId is not recommended.

Consider the following scenario:

  1. A publish request made with eagerIdGeneration enabled and deduplicationId set to "ECHO". Hotsock received the message and the message ID in its response is 01H62H35Q7JJBDB4EE5XA44CHV.
  2. Due to unstable network conditions, the requestor did not receive this response.
  3. Since the requestor saw the publish as a failure, they re-publish the message with the same deduplicationId set to "ECHO". This time the response message ID is 01H62H8HYRCY1F6ZS85BX24B9R but since the initial message was already received, this follow-up message will never be processed and no message with the second 01H62H8HYRCY1F6ZS85BX24B9R ID will ever be processed or sent to channel subscribers.

Deduplication is handled internally by SQS. Since messages are accepted by SQS successfully even when they are duplicates, there's no way for Hotsock to indicate in the message publishing response that a message is a duplicate.

emitPubSubEvent

Boolean (optional) - Whether or not this message will trigger a backend pub/sub event to SNS/EventBridge. This setting has no effect if both SNS and EventBridge events are disabled globally. Default is false.

event

String (required) - The name of the event to publish to the channel. This can be any string up to 128 characters, but must not begin with hotsock. and must not contain any asterisk (*) characters.

store

Integer (optional) - The message retention duration in seconds. 0 is the default if unspecified, which does not save message data. -1 keeps the message forever. The highest number you can specify here is 3155695200, roughly 100 years. For example, setting this to 2592000 (60 seconds * 60 minutes * 24 hours * 30 days) would store the message for 30 days.