Reputation: 678
Blazor server is a fantastic technology, but it constantly breaks with SignalR not being able to reconnect to the server.
How would one fix this in production? I'm having people leaving their laptops in sleep or putting phone with website for a 5 seconds away, than - "Attempting to reconnect".
And always failed. Users are waiting just to see "Reload" button.
Hot to overcome this issue and force reconnect SignalR, even if website was not active in mobile browsers or browsers of sleeping pc?
Upvotes: 20
Views: 12691
Reputation: 198
I know this is an old question and my answer may be irrelevant, but it may help too!
I had the same problem with Blazor in production: Continuously (every 1 minute) getting the reconnect error, but everything else (Blazor functionalities) had worked well. I am using Apache Linux to host my Blazor app. I figured out that the web socket connection was failing with a 502 error, and Blazor tried to reconnect it, but it would fall again. Finally, I understood that the problem is the bad configuration for Apache. I changed the conf from
<VirtualHost *:80>
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
</VirtualHost>
to
<VirtualHost *:80>
ProxyPass / ws://127.0.0.1:5000/
ProxyPassReverse / ws://127.0.0.1:5000/
</VirtualHost>
and it completely solved my problem!
Upvotes: 1
Reputation: 1040
For a simpler solution than Mister Magoo, you could use:
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start().then(() => {
Blazor.defaultReconnectionHandler._reconnectCallback = function (d) {
document.location.reload();
}
});
</script>
This keeps the original startup process and just adds a reload when connection goes down.
Upvotes: 1
Reputation: 8974
Blazor has built in options for customising the startup process
and to Configure the SignalR client for Blazor Server apps
They have even added a sample for how to automatically reload when reconnecting fails.
autostart="false"
and register your boot.js
script<body>
...
<div id="reconnect-modal" style="display: none;"></div>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script src="boot.js"></script>
</body>
(() => {
const maximumRetryCount = 3;
const retryIntervalMilliseconds = 5000;
const reconnectModal = document.getElementById('reconnect-modal');
const startReconnectionProcess = () => {
reconnectModal.style.display = 'block';
let isCanceled = false;
(async () => {
for (let i = 0; i < maximumRetryCount; i++) {
reconnectModal.innerText = `Attempting to reconnect: ${i + 1} of ${maximumRetryCount}`;
await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));
if (isCanceled) {
return;
}
try {
const result = await Blazor.reconnect();
if (!result) {
// The server was reached, but the connection was rejected; reload the page.
location.reload();
return;
}
// Successfully reconnected to the server.
return;
} catch {
// Didn't reach the server; try again.
}
}
// Retried too many times; reload the page.
location.reload();
})();
return {
cancel: () => {
isCanceled = true;
reconnectModal.style.display = 'none';
},
};
};
let currentReconnectionProcess = null;
Blazor.start({
reconnectionHandler: {
onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
onConnectionUp: () => {
currentReconnectionProcess?.cancel();
currentReconnectionProcess = null;
},
},
});
})();
Upvotes: 25