Skip to content

Commit 9390d6d

Browse files
fixup! EDU-1469: Re-writes idempotent publishing section to improve clarity to the reader
1 parent 5ad8e5d commit 9390d6d

File tree

1 file changed

+248
-26
lines changed

1 file changed

+248
-26
lines changed

content/channels/index.textile

Lines changed: 248 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -753,66 +753,288 @@ channel.Publish(context.Background(), "action", "boom!")
753753

754754
h3(#idempotency). Idempotent publish
755755

756-
Ably supports idempotent publishing through both REST and Realtime methods. This feature prevents the processing or forwarding duplicate messages when publishing the same message multiple times under certain network conditions or due to client reattempts. Idempotent publishing involves associating each message with a unique ID. The system then uses this ID to prevent further processing of any message published again with the same ID, recognizing it as a duplicate.
756+
Ably supports idempotent publishing through its REST and realtime interfaces, ensuring that duplicate messages are not processed or forwarded.
757757

758-
Ably's SDK automatically add IDs to messages to ensure idempotent handling. This functionality applies to both REST and realtime publishing. For library versions older than 1.2, enabling idempotent REST publishing was not the default and required activation using the @idempotentRestPublishing@ "@ClientOptions@":/api/rest-sdk#client-options. However, starting with version 1.2, its enabled by default.
759-
You can publish idempotently through Ably's SDK REST and realtime interfaces. Idempotent publishing ensures that duplicate messages published multiple times due to network conditions or client retries are not processed or forwarded again.
758+
Idempotent publishing automatically assigns each message a unique ID, which prevents further processing if the same message is published again, recognizing it as a duplicate. This is essential for handling retries in poor network conditions.
760759

761-
Ably's REST and realtime SDKs automatically add unique IDs to messages. Each message is associated with a unique ID to prevent the processing of duplicates. If a message is published again with the same ID, it is recognized as a duplicate and ignored.
762-
763-
In some cases, achieving idempotency requires a client-supplied ID, especially in scenarios where it's impractical to maintain a single continuously active client instance, such as during a publisher restart or when preserving idempotency across an entire message processing pipeline that involves an upstream system using message IDs. In these situations, specifying a custom message ID for REST and realtime publishing maintains idempotency.
764-
In some cases, achieving idempotency requires specifying a clientId. This is especially important when maintaining a single continuously active client instance is impractical, such as during a publisher restart or when ensuring idempotency across an entire message processing pipeline involving an upstream system using message IDs. Specifying a custom message ID for REST and realtime publishing helps maintain idempotency in these situations.
760+
In certain instances, idempotent publishing requires a client-supplied ID. This is particularly useful when it is impractical to maintain a single, continuously active client instance, such as during a publisher restart or when maintaining idempotency across an entire message processing pipeline involving an upstream system using message IDs. Specifying a custom message ID for REST and realtime publishing in these scenarios ensures idempotency.
765761

766762
<aside data-type='note'>
767763
<p>From version 1.2, idempotent publishing is enabled by default for both REST and realtime interfaces. In earlier versions, enabling idempotent REST and realtime publishing was not the default and required activation using the @idempotentRestPublishing@ option in "@ClientOptions@.":/api/rest-sdk#client-options</p>
768764
</aside>
769765

770-
The following example manually specifies a message ID:
771766
The following example manually specifies a message ID:
772767

773768
```[realtime_javascript]
774-
const rest = new Ably.realtime.Promise('{{API_KEY}}');
775-
const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
776-
await channel.publish([{data: 'payload', id: 'unique123'}]);
769+
const realtime = new Ably.Realtime = '{{API_KEY}}';
770+
const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
771+
const message = [{ data: 'payload', id: 'unique123' }];
772+
773+
try {
774+
await channel.publish(message);
775+
console.log('Message published successfully');
776+
} catch (err) {
777+
console.log('Failed to publish message:', err.message);
778+
}
777779
```
778780

779781
```[rest_javascript]
780-
const rest = new Ably.Rest('{{API_KEY}}');
781-
const channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
782-
await channel.publish([{data: 'payload', id: 'unique123'}]);
782+
const rest = new Ably.Rest = '{{API_KEY}}';
783+
const channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
784+
const message = [{ data: 'payload', id: 'unique123' }];
785+
786+
try {
787+
await channel.publish(message);
788+
console.log('Message published successfully');
789+
} catch (err) {
790+
console.log('Failed to publish message:', err.message);
791+
}
783792
```
784793

785-
```[rest_go]
786-
rest, err := ably.NewREST(
794+
```[realtime_nodejs]
795+
const realtime = new Ably.Realtime = '{{API_KEY}}';
796+
const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
797+
const message = [{ data: 'payload', id: 'unique123' }];
798+
799+
try {
800+
await channel.publish(message);
801+
console.log('Message published successfully');
802+
} catch (err) {
803+
console.log('Failed to publish message:', err.message);
804+
}
805+
```
806+
807+
```[rest_nodejs]
808+
const rest = new Ably.Rest = '{{API_KEY}}';
809+
const channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
810+
const message = [{ data: 'payload', id: 'unique123' }];
811+
812+
try {
813+
await channel.publish(message);
814+
console.log('Message published successfully');
815+
} catch (err) {
816+
console.log('Failed to publish message:', err.message);
817+
}
818+
```
819+
820+
```[realtime_ruby]
821+
realtime = Ably::Realtime.new(key: '{{API_KEY}}')
822+
channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}')
823+
824+
begin
825+
channel.publish(name: 'example', data: 'payload', id: 'unique123')
826+
puts 'Realtime message published successfully'
827+
rescue => e
828+
puts "Failed to publish realtime message: #{e.message}"
829+
end
830+
```
831+
832+
```[rest_ruby]
833+
rest = Ably::Rest.new(key: '{{API_KEY}}')
834+
channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}')
835+
836+
begin
837+
channel.publish(name: 'example', data: 'payload', id: 'unique123')
838+
puts 'REST message published successfully'
839+
rescue => e
840+
puts "Failed to publish REST message: #{e.message}"
841+
end
842+
```
843+
844+
```[realtime_python]
845+
realtime = AblyRealtime('{{API_KEY}}')
846+
channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}')
847+
await channel.publish([{data: 'payload', id: 'unique123'}])
848+
849+
def message_handler(message):
850+
if message.client_id in processed_messages:
851+
print("Duplicate message received.")
852+
else:
853+
print(f"Processing message: {message.data}")
854+
processed_messages.add(message.client_id)
855+
```
856+
857+
```[rest_python]
858+
rest = AblyRest('{{API_KEY}}')
859+
channel = rest.channels.get('{{RANDOM_CHANNEL_NAME}}')
860+
await channel.publish([{data: 'payload', id: 'unique123'}])
861+
862+
def message_handler(message):
863+
if message.client_id in processed_messages:
864+
print("Duplicate message received.")
865+
else:
866+
print(f"Processing message: {message.data}")
867+
processed_messages.add(message.client_id)
868+
```
869+
870+
```[rest_PHP]
871+
$rest = new Ably\AblyRest('{{API_KEY}}');
872+
$channel = $rest->channels->get('{{RANDOM_CHANNEL_NAME}}')
873+
$channel->publish([{data: 'payload', id: 'unique123'}]);
874+
```
875+
876+
```[realtime_java]
877+
ClientOptions options = new ClientOptions('{{API_KEY}}');
878+
AblyRealtime ably = new AblyRealtime(options);
879+
Channel channel = ably.channels.get('{{RANDOM_CHANNEL_NAME}}');
880+
881+
Message message = new Message();
882+
message.data = "payload";
883+
message.id = "unique123";
884+
885+
channel.subscribe(msg -> {
886+
if (processedMessages.contains(msg.id)) {
887+
System.out.println("Duplicate message received.");
888+
} else {
889+
System.out.println("Processing message: " + msg.data);
890+
processedMessages.add(msg.id);
891+
}
892+
});
893+
```
894+
895+
```[rest_java]
896+
ClientOptions options = new ClientOptions('{{API_KEY}}');
897+
AblyRest ably = new AblyRest(options);
898+
Channel channel = ably.channels.get('{{RANDOM_CHANNEL_NAME}}');
899+
900+
Message message = new Message();
901+
message.data = "payload";
902+
message.id = "unique123";
903+
904+
channel.subscribe(msg -> {
905+
if (processedMessages.contains(msg.id)) {
906+
System.out.println("Duplicate message received.");
907+
} else {
908+
System.out.println("Processing message: " + msg.data);
909+
processedMessages.add(msg.id);
910+
}
911+
});
912+
```
913+
914+
```[realtime_csharp]
915+
ARTRealtime *realtime = [[ARTRealtime alloc] initWithKey:@"{{API_KEY}}"];
916+
ARTRealtimeChannel *channel = [realtime.channels get:@"{{RANDOM_CHANNEL_NAME}}"];
917+
918+
[channel publish:@"example" data:@"payload" id:@"unique123" callback:^(ARTErrorInfo *error) {
919+
if (error) {
920+
NSLog(@"Error publishing message: %@", error.message);
921+
} else {
922+
NSLog(@"Message published successfully");
923+
}
924+
}];
925+
```
926+
927+
```[rest_csharp]
928+
ARTRealtime *rest = [[ARTRealtime alloc] initWithKey:@"{{API_KEY}}"];
929+
ARTRealtimeChannel *channel = [rest.channels get:@"{{RANDOM_CHANNEL_NAME}}"];
930+
931+
[channel publish:@"example" data:@"payload" id:@"unique123" callback:^(ARTErrorInfo *error) {
932+
if (error) {
933+
NSLog(@"Error publishing message: %@", error.message);
934+
} else {
935+
NSLog(@"Message published successfully");
936+
}
937+
}];
938+
```
939+
940+
```[realtime_swift]
941+
let realtime = ARTRealtime(key: "{{API_KEY}}")
942+
let channel = realtime.channels.get("{{RANDOM_CHANNEL_NAME}}")
943+
944+
channel.publish("example", data: "message data", id: "unique123") { error in
945+
if let error = error {
946+
print("Error publishing message: \(error)")
947+
} else {
948+
print("Message published successfully")
949+
}
950+
}
951+
```
952+
953+
```[rest_swift]
954+
let rest = ARTRest(key: "{{API_KEY}}")
955+
var channel = rest.channels.get("{{RANDOM_CHANNEL_NAME}}")
956+
957+
channel.publish([ARTMessage(name: "example", data: "message data", id: "unique123")]) { error in
958+
if let error = error {
959+
print("Error publishing message: \(error)")
960+
} else {
961+
print("Message published successfully")
962+
}
963+
}
964+
```
965+
966+
```[realtime_flutter]
967+
final channel = _realtime.channels.get('{{RANDOM_CHANNEL_NAME}}');
968+
await channel.publish(name: 'example', data: 'message data');
969+
970+
Future<void> initializeAndPublish(String apiKey, String channelName, String eventName, String data) async {
971+
if (_realtime == null) {
972+
_realtime = ably.Realtime(key: apiKey);
973+
}
974+
975+
if (_channel == null || _channel.name != channelName) {
976+
_channel = _realtime.channels.get(channelName);
977+
}
978+
979+
await _channel.publish(name: eventName, data: data);
980+
}
981+
```
982+
983+
```[rest_flutter]
984+
final channel = _rest.channels.get('{{RANDOM_CHANNEL_NAME}}');
985+
await channel.publish(name: 'example', data: 'message data');
986+
987+
Future<void> initializeAndPublish(String apiKey, String channelName, String eventName, String data) async {
988+
if (_rest == null) {
989+
_rest = ably.Realtime(key: apiKey);
990+
}
991+
992+
if (_channel == null || _channel.name != channelName) {
993+
_channel = _realtime.channels.get(channelName);
994+
}
995+
996+
await _channel.publish(name: eventName, data: data);
997+
}
998+
```
999+
1000+
```[realtime_go]
1001+
realtime, err := ably.NewRealtime(
7871002
ably.WithKey("{{API_KEY}}"))
7881003
if err != nil {
7891004
log.Fatalf("Error creating Ably client: %v", err)
7901005
}
7911006

792-
channel := rest.Channels.Get("{{RANDOM_CHANNEL_NAME}}")
1007+
channel := realtime.Channels.Get("{{RANDOM_CHANNEL_NAME}}")
7931008

7941009
message := &ably.Message{
7951010
Data: "payload",
7961011
ID: "unique123",
7971012
}
7981013

799-
// Publish the message to the channel
8001014
err = channel.Publish(context.Background(), "eventName", message)
8011015
if err != nil {
8021016
log.Fatalf("Error publishing message: %v", err)
8031017
}
8041018
```
8051019

806-
```[rest_java]
807-
ClientOptions options = new ClientOptions("{{API_KEY}}");
808-
AblyRealtime ably = new AblyRealtime(options);
809-
Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}");
1020+
```[rest_go]
1021+
rest, err := ably.NewREST(
1022+
ably.WithKey("{{API_KEY}}"))
1023+
if err != nil {
1024+
log.Fatalf("Error creating Ably client: %v", err)
1025+
}
8101026

811-
Message message = new Message();
812-
message.data = "payload";
813-
message.id = "unique123";
1027+
channel := rest.Channels.Get("{{RANDOM_CHANNEL_NAME}}")
8141028

815-
channel.publish(new Message[]{message});
1029+
message := &ably.Message{
1030+
Data: "payload",
1031+
ID: "unique123",
1032+
}
1033+
1034+
err = channel.Publish(context.Background(), "eventName", message)
1035+
if err != nil {
1036+
log.Fatalf("Error publishing message: %v", err)
1037+
}
8161038
```
8171039

8181040
If manually specifying message IDs, it is important to be aware of how messages are published when calling the "publish()":/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.

0 commit comments

Comments
 (0)