Back

Trying to understand realtime subscriptions...

  • 0
  • Self Hosted
  • Databases
  • Apple
  • Realtime
Rando
6 May, 2024, 19:28

I'm self-hosting Appwrite version 1.5 as a backend for an iOS app and trying to leverage the realtime module with the Apple SDK.

It's taken me a couple of days to start to get any response at all from it, but now that I am, I have a question.

Is it true that if I want to be alerted when a new document is created in a specific collection, I have to subscribe to the channel:

TypeScript
"databases.<mydb_id>.collections.<mycollection_id>.documents"

...and that I cannot subscribe to:

TypeScript
"databases.<mydb_id>.collections.<mycollection_id>.documents.*.create"

... and that that means I will receive an event with a payload comprised of the full document, for every document that is updated in this collection while my subscription is active - and not just the newly created documents that I am interested in? Even if I ignore events that are not .create events, there will be a LOT of extra data crossing the internet and significant unnecessary local processing.

Documents in this particular collection are expected to be updated frequently - every few seconds but I only need those updates from devices that have subscribed to a specific document. This process to listen for new documents is intended to present a list of documents the user can choose ONE of - after which I will start a new subscription to listen to just events pertaining to that one document. (But there could very well be thousands of documents that are being updated every 2-3 seconds.)

Am I misunderstanding how this works?
Is there any way to eliminate all that waste and to get only the events and payloads for newly created documents?

TL;DR
Developers are having issues with their real-time subscriptions setup in Appwrite SDK for Apple. They are confused about how URLs are passed into the socket and are experiencing problems with adding new channels to subscriptions. Despite trying various solutions, the second subscription doesn't receive any events. A workaround involving creating a second instance of Realtime class temporarily resolved the issue. The developer shares code snippets, asks for advice on debugging, and eventually considers it may be a bug in the SDK code. Further troubleshooting includes checking endpoint settings, closing subscriptions, and verifying code implementation. The conversation involves multiple messages due to character limits. Solution: One successful workaround involved creating a
TomHeger
6 May, 2024, 19:42

Yes, as far as I see that’s true, so it is not possible

Rando
9 May, 2024, 22:44

I also updated the code in both functions to call:

TypeScript
realtime.subscribe(channel: channel)

instead of

TypeScript
realtime.subscribe(channels: Set(channelArray))

but there is no difference in behavior.

Rando
9 May, 2024, 23:16

I got an ugly workaround working - but only as a troubleshooting aid. If I instantiate a 2nd instance of Realtime() like so:

TypeScript
class Appwrite {
    static let shared = Appwrite()
    
    var client: Client
    var account: Account
    var databases: Databases
    var functions: Functions
    **var realtime: Realtime**
    **var realtime2: Realtime**
    var gameUpdateSubscription: RealtimeSubscription?
    var gameInProgressCollectionSubscription: RealtimeSubscription?
    var gameInProgressTestSub: RealtimeSubscription?

    public init() {
        self.client = Client()
            .setEndpoint("https://appwrite.myserver.app/v1")
            .setProject("6605dc1c00272e912cc8") // Your project ID
        
        self.account = Account(client)
        self.functions = Functions(client)
        **self.realtime = Realtime(client)**
        **self.realtime2 = Realtime(client)**
        self.databases = Databases(client)

    }

And I subscribe to the first listener with realtime.subscribe() and the second listener with realtime2.subscribe() - then both listeners work properly at the same time (but presumably with 2 websocket connections instead of just the one). It's not something I can use - but it does prove (again) that both subscribe() calls are valid.

Steven
9 May, 2024, 23:31

Can you add print statements here to check if data is coming through from Appwrite?

Steven
9 May, 2024, 23:32

Wait...the subscribed to channels is all the same πŸ‘€

Rando
9 May, 2024, 23:33

Where do you want me to add the print statments?

Steven
9 May, 2024, 23:35

What I linked in my message

Rando
9 May, 2024, 23:39

Not sure where you mean...

Steven
9 May, 2024, 23:48

This message ☝️

Rando
9 May, 2024, 23:52

Yeah - and that's where I've been adding a bunch of print statements - but I don't know what you mean by "to verify the data is coming through". In which function? We know "some" data is coming through because I get the events for the first subscription. Where do I need to add logging to log information about the event that is NOT coming through? To me, it sounds like you're saying "Raise your hand if you are not here!" πŸ˜„

Steven
9 May, 2024, 23:56

Do you not see that link on the data word?

Rando
10 May, 2024, 00:02

Yes - but I thought it just linked to "Realtime.swift" so I didn't click it and just opened the file locally. I didn't realize that it pointed to a specific line within it! But instead of just repeating the same link over and over when I obviously didn't understand what you meant, perhaps you might have elaborated sooner - or simply said "in the onMessage() function"? lol I'll add a print statement now.

Rando
10 May, 2024, 00:18

The output is too long to paste, but I started the app which initiates the first listener. OnMessage() didn't appear in the log. Then I created a new game from another device and the original device received the event and logged data from the onMessage() call. Then I paused the game on the 2nd device and tapped the new game on the test device to initiate the subscription.

TypeScript
2024-05-09 20:16:27 - tableView(_:didSelectRowAt:):  Subscribing to game updates for docId: 663d66bfa93d0c5b5799
2024-05-09 20:16:27 - fetchGameInProgress(docId:): Received 663d66bfa93d0c5b5799 lastUpdated: 2024-05-10T00:13:53.551+00:00
2024-05-09 20:16:27 - fetchGameInProgress(docId:): Received Document with ID: 663d66bfa93d0c5b5799
2024-05-09 20:16:27 - fetchGameInProgress(docId:): -- game-in-progress Game ID: 2VL6
2024-05-09 20:16:27 - subscribeToGameUpdates(docId:callbackVC:):  Subscribing to channels: databases.6605e1b40033ee096f28.collections.games-in-progress.documents.663d66bfa93d0c5b5799
Subscribed (A) to channel: databases.6605e1b40033ee096f28.collections.games-in-progress.documents.663d66bfa93d0c5b5799
Subscribed (B) to 1 channels:
subscribe:channels:payloadType:callback:()-- Channel: databases.6605e1b40033ee096f28.collections.games-in-progress.documents.663d66bfa93d0c5b5799
subscribe:channels:payloadType:callback:()  Active Subscriptions: 2
-- Active Subscription Key:2 CB: ["databases.6605e1b40033ee096f28.collections.games-in-progress.documents.663d66bfa93d0c5b5799"]
-- Active Subscription Key:1 CB: ["databases.6605e1b40033ee096f28.collections.gameinprogress-docids.documents"]
2024-05-09 20:16:27 - subscribeToGameUpdates(docId:callbackVC:): gameUpdateSubscription established: Optional(Appwrite.RealtimeSubscription)

Then I resumed the game on the 2nd device - but no events or onMessage() data was received by the test device.

Rando
10 May, 2024, 00:21

My logging shows that there are 2 active subscriptions (like it should). But no events are received for the second one.

Steven
10 May, 2024, 01:13

An event only comes through when there's some operation. Nothing comes through when you first subscribe

Rando
10 May, 2024, 01:14

Understood. But events should have come through after I resumed the game on the 2nd device - but they didn't.

Rando
10 May, 2024, 01:15

If I restart the test device with the first subscription commented out - those game events DO come through properly.

Rando
10 May, 2024, 01:15

So it seems like when there is more than one subscription, the 2nd one doesn't get properly registered on the server?

Steven
10 May, 2024, 01:50

@Jake, it looks like we only pass the url (and channels) in once, so a second subscribe call won't get the new channels, right?

Jake
10 May, 2024, 04:52

We only maintain one connection but a second call to subscribe will add the new channels, close the current connection, then open a new one with all channels included. The events that are received are then sent to the right callback depending on the channels they subscribed with

Steven
10 May, 2024, 04:55

How do the new channels get added because it seems like the url is only passed in when the socket is initialized and not on close and connect? See https://github.com/appwrite/sdk-for-apple/blob/c39030db9af1e2dd7b36f8df45f838c5f7dfb0da/Sources/Appwrite/Services/Realtime.swift#L41

Jake
10 May, 2024, 04:59

New channels are added on subscribe here then added to URL here

Steven
10 May, 2024, 05:00

Ya but how does the url get passed into the socket?

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more