Skip to content

Commit 7695c22

Browse files
committed
Update idempotent publishing to not solely focus on REST
1 parent e30ae8b commit 7695c22

File tree

1 file changed

+141
-21
lines changed

1 file changed

+141
-21
lines changed

content/pub-sub/advanced.textile

Lines changed: 141 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -935,54 +935,174 @@ h3(#idempotency). Idempotent publishing
935935

936936
Idempotency ensures that multiple publishes of the same message cannot result in duplicate messages.
937937

938-
It is possible that a client publishing a message using the REST interface may not receive acknowledgement of receipt from Ably, due to issues such as network failure outside of Ably's control. Clients will internally attempt to re-publish messages in these instances.
939-
940938
When idempotent publishing is enabled, the Ably SDK will internally assign a unique ID to each message which ensures that subsequent retry attempts cannot result in duplicate messages. Idempotent publishing is enabled by default in all latest Ably SDKs. It can be disabled by setting the @idempotentRestPublishing@ "@ClientOptions@":/docs/api/rest-sdk#client-options to @false@.
941939

942-
Note that Ably can only detect duplicate messages within a 2-minute window after the original message, with the same ID, is published. If a message with the same ID is published after this 2-minute window, it will be treated as a new message.
940+
In some cases you may wish to set the unique message ID yourself to achieve idempotency, such as:
943941

944-
You can also specify message IDs externally. The following is an example of how you might do this:
942+
* To ensure idempotency when a publisher instance might be restarted, and continuous activity cannot be guaranteed.
943+
* To integrate with an upstream system that uses message IDs, to ensure idempotency across an entire message processing pipeline.
945944

946-
```[rest_javascript]
947-
const rest = new Ably.Rest('{{API_KEY}}');
948-
const channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
949-
await channel.publish([{data: 'payload', id: 'unique123'}]);
945+
If setting your own message IDs be aware of the "restrictions":https://faqs.ably.com/client-specified-message-id-restrictions-for-multiple-messages-published-atomically on its format when publishing messages atomically.
946+
947+
<aside data-type='note'>
948+
<p>Ably can only detect duplicate messages within a 2-minute window after the original message, with the same ID, is published. If a message with the same ID is published after this 2-minute window, it will be treated as a new message.</p>
949+
</aside>
950+
951+
The following is an example of specifying message IDs yourself when publishing:
952+
953+
```[realtime_javascript]
954+
const realtime = new Ably.Realtime = '{{API_KEY}}';
955+
const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
956+
const message = [{ data: 'payload', id: 'unique123' }];
950957
```
951958

952-
```[rest_go]
953-
rest, err := ably.NewREST(
959+
```[realtime_nodejs]
960+
const realtime = new Ably.Realtime = '{{API_KEY}}';
961+
const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
962+
const message = [{ data: 'payload', id: 'unique123' }];
963+
```
964+
965+
```[realtime_ruby]
966+
realtime = Ably::Realtime.new(key: '{{API_KEY}}')
967+
channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}')
968+
channel.publish(name: 'example', data: 'payload', id: 'unique123')
969+
```
970+
971+
```[realtime_python]
972+
realtime = AblyRealtime('{{API_KEY}}')
973+
channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}')
974+
await channel.publish([{data: 'payload', id: 'unique123'}])
975+
```
976+
977+
```[realtime_java]
978+
ClientOptions options = new ClientOptions('{{API_KEY}}');
979+
AblyRealtime ably = new AblyRealtime(options);
980+
Channel channel = ably.channels.get('{{RANDOM_CHANNEL_NAME}}');
981+
982+
Message message = new Message();
983+
message.data = "payload";
984+
message.id = "unique123";
985+
```
986+
987+
```[realtime_csharp]
988+
ARTRealtime *realtime = [[ARTRealtime alloc] initWithKey:@"{{API_KEY}}"];
989+
ARTRealtimeChannel *channel = [realtime.channels get:@"{{RANDOM_CHANNEL_NAME}}"];
990+
channel publish:@"example" data:@"payload" id:@"unique123" callback:^(ARTErrorInfo *error)
991+
```
992+
993+
```[realtime_swift]
994+
let realtime = ARTRealtime(key: "{{API_KEY}}")
995+
let channel = realtime.channels.get("{{RANDOM_CHANNEL_NAME}}")
996+
channel.publish("example", data: "message data", id: "unique123")
997+
```
998+
999+
```[realtime_objc]
1000+
ARTRealtime *realtime = [[ARTRealtime alloc] initWithKey:("{{API_KEY}}"));
1001+
ARTRealtimeChannel *channel = [realtime.channels get:("{{RANDOM_CHANNEL_NAME}}");
1002+
[channel.publish("example", data: "message data", id: "unique123")];
1003+
```
1004+
1005+
```[realtime_flutter]
1006+
final clientOptions = ably.ClientOptions(key: '{{API_KEY}}');
1007+
final realtime = ably.Realtime(options: clientOptions);
1008+
final channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
1009+
await message = ably.Message(data: 'payload', id: 'unique123');
1010+
```
1011+
1012+
```[realtime_go]
1013+
realtime, err := ably.NewRealtime(
9541014
ably.WithKey("{{API_KEY}}"))
9551015
if err != nil {
9561016
log.Fatalf("Error creating Ably client: %v", err)
9571017
}
9581018

959-
channel := rest.Channels.Get("{{RANDOM_CHANNEL_NAME}}")
1019+
channel := realtime.Channels.Get("{{RANDOM_CHANNEL_NAME}}")
9601020

9611021
message := &ably.Message{
9621022
Data: "payload",
9631023
ID: "unique123",
9641024
}
1025+
```
9651026

966-
// Publish the message to the channel
967-
err = channel.Publish(context.Background(), "eventName", message)
968-
if err != nil {
969-
log.Fatalf("Error publishing message: %v", err)
970-
}
1027+
```[rest_javascript]
1028+
const rest = new Ably.Rest = '{{API_KEY}}';
1029+
const channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
1030+
const message = [{ data: 'payload', id: 'unique123' }];
1031+
```
1032+
1033+
```[rest_nodejs]
1034+
const rest = new Ably.Rest = '{{API_KEY}}';
1035+
const channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
1036+
const message = [{ data: 'payload', id: 'unique123' }];
1037+
```
1038+
1039+
```[rest_ruby]
1040+
rest = Ably::Rest.new(key: '{{API_KEY}}')
1041+
channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}')
1042+
channel.publish(name: 'example', data: 'payload', id: 'unique123')
1043+
```
1044+
1045+
```[rest_python]
1046+
rest = AblyRest('{{API_KEY}}')
1047+
channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}')
1048+
await channel.publish([{data: 'payload', id: 'unique123'}])
1049+
```
1050+
1051+
```[rest_php]
1052+
$rest = new Ably\AblyRest('{{API_KEY}}');
1053+
$channel = $rest->channels->get('{{RANDOM_CHANNEL_NAME}}')
1054+
$channel->publish([{data: 'payload', id: 'unique123'}]);
9711055
```
9721056

9731057
```[rest_java]
974-
ClientOptions options = new ClientOptions("{{API_KEY}}");
975-
AblyRealtime ably = new AblyRealtime(options);
976-
Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}");
1058+
ClientOptions options = new ClientOptions('{{API_KEY}}');
1059+
AblyRest ably = new AblyRest(options);
1060+
Channel channel = ably.channels.get('{{RANDOM_CHANNEL_NAME}}');
9771061

9781062
Message message = new Message();
9791063
message.data = "payload";
9801064
message.id = "unique123";
1065+
```
9811066

982-
channel.publish(new Message[]{message});
1067+
```[rest_csharp]
1068+
ARTRealtime *rest = [[ARTRealtime alloc] initWithKey:@"{{API_KEY}}"];
1069+
ARTRealtimeChannel *channel = [rest.channels get:@"{{RANDOM_CHANNEL_NAME}}"];
1070+
channel publish:@"example" data:@"payload" id:@"unique123" callback:^(ARTErrorInfo *error)
9831071
```
9841072

985-
If manually specifying message IDs, it is important to be aware of how messages are published when calling the "publish()":/docs/api/rest-sdk/channels#publish method with an array of messages. See this "FAQ":https://faqs.ably.com/client-specified-message-id-restrictions-for-multiple-messages-published-atomically for further information.
1073+
```[rest_swift]
1074+
let rest = ARTRest(key: "{{API_KEY}}")
1075+
var channel = rest.channels.get("{{RANDOM_CHANNEL_NAME}}")
1076+
channel.publish("example", data: "message data", id: "unique123")
1077+
```
1078+
1079+
```[rest_objc]
1080+
ARTRest *rest = [[ARTRest alloc] initWithKey:("{{API_KEY}}"));
1081+
ARTRestChannel *channel = [rest.channels get:("{{RANDOM_CHANNEL_NAME}}");
1082+
[channel.publish("example", data: "message data", id: "unique123")];
1083+
```
1084+
1085+
```[rest_flutter]
1086+
final clientOptions = ably.ClientOptions(key: '{{API_KEY}}');
1087+
final rest = ably.Rest(options: clientOptions);
1088+
final channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
1089+
await message = ably.Message(data: 'payload', id: 'unique123');
1090+
```
1091+
1092+
```[rest_go]
1093+
rest, err := ably.NewREST(
1094+
ably.WithKey("{{API_KEY}}"))
1095+
if err != nil {
1096+
log.Fatalf("Error creating Ably client: %v", err)
1097+
}
1098+
1099+
channel := rest.Channels.Get("{{RANDOM_CHANNEL_NAME}}")
1100+
1101+
message := &ably.Message{
1102+
Data: "payload",
1103+
ID: "unique123",
1104+
}
1105+
```
9861106

9871107
h3(#publish-on-behalf). Publishing on behalf of a realtime connection
9881108

0 commit comments

Comments
 (0)