Messages
A message is the unit of data that flows through RelayX.
Messages are what producers send and what subscribers receive. Everything else in RelayX exists to move, deliver, or store messages.
What is a Message?
Think of a message as:
- A payload of data
- Sent by a producer
- Delivered to one or more subscribers
- In a defined order (within a topic)
- With clear rules about retries and duplication
RelayX messages are intentionally simple. They are not jobs, not commands, and not workflows. They are just data.
Key Properties
- Immutable — Once accepted by the backend, messages cannot be changed
- Ordered per topic — Messages are delivered in order within a single topic
- At-least-once delivery — Messages may be delivered more than once if a subscriber crashes
- Backend deduplicated — RelayX deduplicates at ingestion, not at delivery
A message does not represent success, failure, or completion by itself. Those concepts live in your subscriber logic.
Message Data Types
RelayX messages support common data types. A message payload can be:
- JSON (objects, arrays)
- String
- Number
// JSON object
await client.publish('events', {
type: 'user.signup',
userId: 123,
metadata: { source: 'web' }
});
// String
await client.publish('logs', 'Server started on port 3000');
// Number
await client.publish('metrics.temperature', 72.5);
RelayX does not enforce a schema. It treats the payload as opaque data. It's your responsibility to ensure producers and subscribers agree on structure and meaning.
Message Ordering
Message ordering is one of the most misunderstood aspects of distributed messaging. Here's what RelayX guarantees—and what it doesn't.
The Core Guarantee
Messages are ordered by backend timestamp within a single topic. There are no ordering guarantees across different topics.
Within a Topic: Ordered ✓
When multiple messages are published to the same topic, subscribers receive them in order:
// Publisher
await client.publish('chat.room1', { text: 'First' });
await client.publish('chat.room1', { text: 'Second' });
await client.publish('chat.room1', { text: 'Third' });
// Subscriber receives in order:
// 1. { text: 'First' }
// 2. { text: 'Second' }
// 3. { text: 'Third' }
This holds even when messages come from different publishers — they're ordered by backend timestamp.
Across Topics: NOT Ordered ✗
When messages go to different topics, there's no ordering guarantee:
// These might arrive in ANY order
await client.publish('orders.created', { orderId: 1 });
await client.publish('inventory.updated', { sku: 'ABC' });
await client.publish('notifications.send', { userId: 123 });
// The inventory update might arrive before the order creation!
Why? Topics may route to different servers, network latency varies, and maintaining global order would kill performance.
Design for Ordering
✅ Good: Related events on the same topic
// All events for order 123 on one topic — they arrive in order
await client.publish('order.123', { type: 'created', data: {...} });
await client.publish('order.123', { type: 'item_added', data: {...} });
await client.publish('order.123', { type: 'payment_completed', data: {...} });
❌ Risky: Related events on different topics
// Payment might arrive before order creation!
await client.publish('orders.created', { orderId: 123 });
await client.publish('payments.completed', { orderId: 123 });
Ordering Summary
| Scenario | Ordered? |
|---|---|
| Same topic, same publisher | ✅ Yes |
| Same topic, different publishers | ✅ Yes (by backend timestamp) |
| Different topics | ❌ No |
| Queue with single consumer | ✅ Yes |
| Queue with multiple consumers | ⚠️ Jobs run in parallel |
Design your topic structure so that ordering within a topic provides the guarantees you need. Don't rely on cross-topic ordering.
Join our Discord server, post your concern & someone from our team will help you out ✌️