mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
6d7c12274e
A SubscriptionGuarantor maintains a set of pending subscriptions, resending the subscribe command unless and until the subscription is confirmed or rejected by the server or cancelled client-side. A race condition in the ActionCable server - where an unsubscribe is sent, followed rapidly by a subscribe, but handled in the reverse order - necessitates this enhancement. Indeed, the subscriptions created and torn down by Turbo Streams amplifies the existence of this race condition.
50 lines
No EOL
1.5 KiB
JavaScript
50 lines
No EOL
1.5 KiB
JavaScript
import logger from "./logger"
|
|
|
|
// Responsible for ensuring channel subscribe command is confirmed, retrying until confirmation is received.
|
|
// Internal class, not intended for direct user manipulation.
|
|
|
|
class SubscriptionGuarantor {
|
|
constructor(subscriptions) {
|
|
this.subscriptions = subscriptions
|
|
this.pendingSubscriptions = []
|
|
}
|
|
|
|
guarantee(subscription) {
|
|
if(this.pendingSubscriptions.indexOf(subscription) == -1){
|
|
logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`)
|
|
this.pendingSubscriptions.push(subscription)
|
|
}
|
|
else {
|
|
logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`)
|
|
}
|
|
this.startGuaranteeing()
|
|
}
|
|
|
|
forget(subscription) {
|
|
logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`)
|
|
this.pendingSubscriptions = (this.pendingSubscriptions.filter((s) => s !== subscription))
|
|
}
|
|
|
|
startGuaranteeing() {
|
|
this.stopGuaranteeing()
|
|
this.retrySubscribing()
|
|
}
|
|
|
|
stopGuaranteeing() {
|
|
clearTimeout(this.retryTimeout)
|
|
}
|
|
|
|
retrySubscribing() {
|
|
this.retryTimeout = setTimeout(() => {
|
|
if (this.subscriptions && typeof(this.subscriptions.subscribe) === "function") {
|
|
this.pendingSubscriptions.map((subscription) => {
|
|
logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`)
|
|
this.subscriptions.subscribe(subscription)
|
|
})
|
|
}
|
|
}
|
|
, 500)
|
|
}
|
|
}
|
|
|
|
export default SubscriptionGuarantor |