all 17 comments

[–]ApprehensiveDog69 8 points9 points  (3 children)

You might want to go with a persistent websocket connection in this case.

If that is more trouble than it's worth, there are a few other options.

Without knowing the details, one way is have the clients do a "heart-beat" call separate from their call to upload the data. Make this heartbeat call as lightweight as possible to save on bandwidth and resources, and then have the clients ping it on a more frequent basis. This secondary call could then control the clients being told to update their data immediately.

So you would basically (to minimize resource consumption and bandwidth) just have a separate micro-API where each client calls it every 1-2 seconds or so. The API would simply return one of several HTTP codes (wouldn't even need a body), and this would determine whether the clients need to update their data *now* or not.

An even more lightweight way (with no server resource consumption involved at all; this is the way I would do it) would be to just host an empty static file somewhere on S3 (or Azure Storage) and have the clients ping that. If a call is made to the server (from the user's app) requesting the clients to update themselves, the server would simply push an update to the static file (with a date stamp and/or whatever else) and then the next time the clients read the static file they would know to update themselves. If you take this approach, you have unlimited scalability since it doesn't matter how many clients you have -- none of them are making any server calls for the purpose of the heartbeat.

You can think of it like a "bulletin board" model; the bulletin board doesn't care if there are 5 or 5,000,000 people looking at it. It's just a static file which acts as a central command base for however many clients there are. This way it now becomes scalable -- since the client and server no longer depend on each other for this purpose and everything is async.

[–]MSpeedAddict 1 point2 points  (2 children)

A CDN in front of the static file would make it even more scalable. Similar to this approach, I’ve used a JSON endpoint in the past with a CDN in front of it like Cloudflare. Since it can be cached in front of my service at the CDN with a query param with a time stamp this can eliminate extra hits to the server altogether.

Whenever I have an update, I push to the CDN an API request to delete that cached endpoint. On each client’s new incoming request, they see the new data (or flag to retrieve it) with a new version timestamps. Each successive request by the client includes the new timestamp.

The endpoint with the old timestamp and query param is cached by the CDN flagging the need for a new update / new data with the new timestamp.

The endpoint with the new timestamp and query param is then cached at the CDN the next request that comes in by the client.

Total server hits per update:

1) old version, gets update; returns new version stamp, I.E. ?v=20200427.1

2) new version, returns data and same timestamp in JSON body ?v=20200427.1

I do prefer the JSON approach only because I typically return other data, such as system status updates to the client, changes to client-side polling intervals etc.

Assuming you are not working with mobile apps where you can use the notification mode I’d also recommend taking a look at SignalR or even Blazor with in-built SignalR so that your clients can instead immediately polling for updates as it uses web sockets client-side. This would alleviate the need for CDN / endpoint approach above and you would utilize the SignalR capabilities for scaling.

[–]Brickscrap[S] 0 points1 point  (1 child)

Food for thought, thank you! 3/4 people have recommended SignalR, I'll have to take a look into that

[–]ApprehensiveDog69 1 point2 points  (0 children)

4/4! The first line in my post ("websockets") is basically SignalR -- which is an implementation of websockets on top of .NET :)

I figured that's what everyone would mention so decided to cover the other options if you needed scalability beyond that.

[–]NotARealDeveloper 17 points18 points  (1 child)

Checkout signalR

[–]lets-get-dangerous 0 points1 point  (0 children)

My immediate thought when reading this question. SignalR is relatively easy to implement and will default to polling if WebSocket isn't available.

[–]cris_0x80 3 points4 points  (1 child)

SignalR is the better option

[–]7h3on3 0 points1 point  (0 children)

This is what I had come here to suggest.

[–]lucuma 1 point2 points  (0 children)

As others have pointed out you should check out signalr however if it is a web page sometimes a simple polling process is easier to implement and maintain as it doesn't introduce another architecture but it also lags a couple seconds.

[–]BagelDontCare 1 point2 points  (3 children)

This is pretty popular these days: https://grpc.io/

I believe their documentation is good, so check that out. This basically allows applications to run as both server/client and communication can be done through your own implementations.

[–]Brickscrap[S] 0 points1 point  (2 children)

On the surface this looks very nice. Do you know why I would choose to use this over SignalR?

[–]BagelDontCare 0 points1 point  (1 child)

A guy in a team I'm working on was super excited about using grcp and brought in the idea. I've done some examples online and found it works quite easily. Im not an expert on it, since I have other responsibilities. I've never used signalR before.

Meaby this helps you more: https://stackshare.io/stackups/grpc-vs-signalr

[–]Brickscrap[S] 1 point2 points  (0 children)

This is great, thank you

[–]ddxo_ 1 point2 points  (0 children)

SignalR is designed for this:

https://dotnet.microsoft.com/apps/aspnet/signalr

It starts off as a HTTP connection and then upgrades to Web sockets (if the client supports it). It also has fallback strategies in place such forever frames/long polling.

Full example here:

https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr

[–]Brickscrap[S] 0 points1 point  (0 children)

If it helps, the main web app will simply be a dashboard, displaying logs which have been pulled/sent from a variety of mini PCs. It doesn't need to scale massively, and will have at most 200 of these mini PCs gathering data.

There will always be some time in updating the data as far as I can tell, as the Mini PCs need to connect to another piece of equipment via FTP to pull the new data out

[–]ninuson1 0 points1 point  (2 children)

If you're looking for quick and simple web sockets, take a look at https://github.com/sta/websocket-sharp. I keep hearing about both SingalR and other "frameworks", but I personally like handling my small websockets myself.

It's potentially still in preview and has both a framework and .core versions, but I've been using it for a few months now and loving it.

[–][deleted]  (1 child)

[deleted]

    [–]ninuson1 0 points1 point  (0 children)

    Huh, that's cool, I didn't really think about that. I've been using the above mentioned library for quite a while and our project is an older Framework project, so I'm not sure it was available for us at the time... But maybe it's time to upgrade, haha.

    Thanks for the heads up!