-
Notifications
You must be signed in to change notification settings - Fork 437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Occasional disconnect, no documented way to monitor or reconnect and handle missed stream actions #1261
Comments
I can't even figure out the relationship between Turbo and ActionCable. I know Turbo uses ActionCable, and I had to edit cable.yml as part of my original configuration. But notably, when I view source for my app there is no
From: https://guides.rubyonrails.org/action_cable_overview.html#client-side-logging That importmap reference doesn't exist. |
Poking around the internals I've managed to wire up a poll interval. In my application.js I simply changed the turbo-rails import and added a little code:
I don't quite understand what it's doing. I'm creating a new consumer, but this must be working over the existing cable connection. Clearly this isn't the consumer that Turbo is using, but I think my creating a new one which I have access to then I can check the status of it. I still haven't been able to find any event I can listen to, but I'm going to proceed with this hack for now. |
Are you using ActionCable itself or something like the <turbo-cable-stream-source channel="Turbo::StreamsChannel" signed-stream-name="..." connected></turbo-cable-stream-source> In my experience, the websocket connection gets regularly lost, even with a stable internet connection. |
@leonvogt Yes, I'm using Can you share more about what conditions you preform a turbo refresh / morph and how you trigger that with javascript? That's exactly what I need to implement next. Here is my motivation, just for more context. My app needs to support users remaining connected for potentially days in a row. The browser may be backgrounded & re-foregrounded, the computer may even go to sleep and come out of sleep. And I want the websocket/stream to be smart enough to manage itself during all of this. Currently, it does not. When I leave my computer unattended for one night and come back the next day, the front-end interactions are no longer working. I have to do a hard refresh of the page to get things working again — that's what I'm trying to solve. |
Sure, my current Stimulus controller looks like this: import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="ws-status"
export default class extends Controller {
static targets = ["streamElement", "onlineIndicator", "offlineIndicator"]
static values = {
autoStart: { type: Boolean, default: true },
autoRefresh: { type: Boolean, default: true },
interval: { type: Number, default: 1000 }
}
connect() {
if (this.autoStartValue) {
this.start()
}
}
disconnect() {
this.stop()
}
start() {
if (!this.hasStreamElementTarget) return;
if (!this.hasOnlineIndicatorTarget) return;
this.interval = setInterval(() => {
if (this.isOnline) {
const wasOffline = this.onlineIndicatorTarget.classList.contains('d-none')
this.onlineIndicatorTarget.classList.remove('d-none')
this.offlineIndicatorTarget.classList.add('d-none')
if (wasOffline && this.autoRefreshValue) {
Turbo.session.refresh(location.href);
}
} else {
this.onlineIndicatorTarget.classList.add('d-none')
this.offlineIndicatorTarget.classList.remove('d-none')
}
}, this.intervalValue)
}
stop() {
clearInterval(this.interval)
}
get isOnline() {
return this.streamElementTargets.every(element => element.hasAttribute('connected'))
}
} And can be used like this: <div class="online-status-indication" data-controller="ws-status">
<%= turbo_stream_from "dashboard", Current.customer.root.id, data: { ws_status_target: "streamElement", turbo_permanent: true } %>
<div data-ws-status-target="onlineIndicator">
<small class="text-muted"><%= t("dashboard.status_online") %></small>
<%= icon('fas', 'circle', class: 'text-success') %>
</div>
<div class="d-none" data-ws-status-target="offlineIndicator">
<small class="text-muted"><%= t("dashboard.status_offline") %></small>
<%= icon('fas', 'circle', class: 'text-danger') %>
<%= link_to dashboard_path, class: "btn btn-outline-secondary btn-sm" do %>
<%= icon('fas', 'sync', class: 'me-2') %>
<%= t('dashboard.refresh') %>
<% end %>
</div>
</div> Please note that this is a quite simple approach and I'm not sure if it fits your described use case. |
Hi @leonvogt I never thanked you for this sample code! It was helpful and I ended up incorporating bits of this. I thought I replied right away but just came back to this issue and I was remiss in doing so. I really appreciate you taking the time to share. |
This issue with monitoring and handling disconnect/reconnect is related to a bigger issue I'm struggling with: missed turbo stream actions. I've now run into situations where my front-end is missing a turbo stream action (1) right before the page finishes rendering and connecting to the stream channel, and (2) when the page disconnects and reconnects for some reason (e.g. browser suspending the tab because you backgrounded it and later made the tab active again) and a stream action is fired during this period. In both cases, when the page finally reconnects, I think it needs some general way of "catching up" missed stream actions. In this other Rails Issue I've opened rails/rails#52420 I discuss one work-around for situation #1 and a small PR I tee'd up was merged in which will help in implementing a hacky solution, but situation #2 is even more common and I think it really speaks to something deeper. |
I can't figure out how to monitor for a websocket disconnection (presumably an event I can listen to) so I can notify the end user.
In my production app, my users occasionally end up in a situation where they miss a turbo stream update. I'm almost certain this is due to flaky internet connection so that the websocket gets dropped. I've seen it happen to me occasionally.
I've been digging through the turbo repo, turbo rails, and actioncable, and reviewing the public docs for all three and I can't find any mention of a disconnect event.
Do we need to simply add this to public docs? Or does one not exist and we need a PR to add one?
The text was updated successfully, but these errors were encountered: