graphql-firebase-subscriptions
v2.5.0
Published
Broadcast graphql messages via firebase realtime database, optional local cache for performance
Downloads
375
Readme
GraphQL Subscriptions through Firebase Realtime Database
This is a GraphQL Subscriptions implementation that uses Firebase Realtime Database as a message broker.
Comparison
Depending on your use-case this may or may not be the tool for you, this implementation is not meant as a way to listen to state updates on persisted data, for that you should probably look at graphql-firestore-subscriptions. This implementation is closer to an alternative to Google PubSub. Now you may wonder, "why not use PuSub then?" well, basically I had concerns that the PubSub documentation stated the performance on low message volumes might not be great on PubSub since the priority was low latency at high load, some graphs I saw showed seconds of latency for the types of volumes I was looking at, whereas I've experienced a more consistent performance from RTDB, but it doesn't go lower with scale like PubSub does. For using PubSub, there's graphql-google-pubsub.
Now Firebase RTDB isn't without latency, not at all! And to alleviate this, this library also provides an optional "local cache", this is really useful if you're running on something like Google Cloud Run where you have multiple instances serving requests. Turning this on will make the library work on an "at-least-once" delivery principle. If something happens (most likely a mutation) on the same instance a subscriber is connected to it will use an internal in-memory EventEmitter and "instantly" forward the message. It will also publish the message to Firestore RTDB and keep the node ID in a short-lived local cache, when the message later arrives, and assuming its ID hasn't expired from the cache, it will simply be ignored and not re-emitted to subscribers connected to the instance that originally received the message.
Usage
By default, the ref /graphql-firebase-subscriptions
in your database will be
used as the root for messages.
import { PubSub } from 'graphql-firebase-subscriptions'
enum Topic {
NEW_COMMENT = 'new-comment'
}
const pubSub = new PubSub()
const Resolvers = {
Subscription: {
newComment: {
subscribe: () => pubSub.asyncIterator(Topic.NEW_COMMENT)
}
},
Mutation: {
async addComment (_, args, ctx) {
const comment = await ctx.dataSources.comments.createOne(args.postId, args.comment)
await pubSub.publish(Topic.NEW_COMMENT, { postId: args.postId, commentId: comment.id })
return comment
}
}
}
Local Cache
Enabling the local cache for speed up is as simple as a boolean
import { PubSub } from 'graphql-firebase-subscriptions'
const pubSub = new PubSub({ localCache: true })
Only New
This flag allows receiving only messages which were published after client subscription to some topic. Default behaviour is to receive all messages which were published and not deleted (see Cleanup section).
import { PubSub } from 'graphql-firebase-subscriptions'
const pubSub = new PubSub({ onlyNew: true })
When creating an asyncIterator you can override this option
import { PubSub } from 'graphql-firebase-subscriptions'
const pubSub = new PubSub({ onlyNew: false })
const iterator = pubSub.asyncIterator(['TOPIC'], { onlyNew: true })
Alternative base ref
You can use an alternative base ref for the message brokerage, useful if you want separate instances with the same topics.
import { PubSub } from 'graphql-firebase-subscriptions'
import { getDatabase } from 'firebase-admin/database'
const pubSub = new PubSub({
ref: getDatabase().ref('/path/to/base/ref')
})
Cleanup
This library requires you to clean up old messages, else it will just keep adding messages to the topics forever. This could slow down message delivery, and it'll waste storage and cost.
To help with this task, the library provides a Firebase Function that works on a Google Cloud Scheduler Trigger. Note that per Firebase's own documentation a cloud scheduler job costs about USD 0.10 per month and requires you to be on the Blaze plan for firebase.
To use it, just generate a handler and re-export it
import getDeletionRoutineFunction from 'graphql-firebase-subscriptions/firebase-functions'
enum Topics {
NEW_COMMENT = 'new-comment'
}
export const pubSubDeletionRoutine = getDeletionRoutineFunction({
topics: Topics,
// -------OPTIONAL-------
// You can overwrite the base ref, if you've done so when using the PubSub
ref: getDatabase.ref('/graphql-firebase-subscriptions'),
// you can override the schedule for the function, by default it runs every
// 10 minutes
schedule: 'every 10 minutes',
// and you can override the maximum time a message should be stored,
// the default is to delete messages older than 10 minutes
maxAge: 600_000
})