Why does the task scheduler often wait one or more frames to replicate remoteevent fires?

I’ve been measuring latency of remoteevents in Play Solo and I have recorded three values that pop up: ~0ms, ~17ms, ~34ms. These 3 values do not deviate beyond 1 millisecond, and these are the only values that would pop up; this suggests that there is 0 latency of the remote actually firing (which makes sense because it’s in Play Solo, so both the client and server are run locally) and that the task scheduler is choosing to wait one or two cycles before actually firing the signal.

I verified this phenomena in a game server by measuring the same delay and comparing most frequent values. I found that there were two extremely common deltas that were consistently printed out, and after doing the math, I found that they were separated by 17 ms (which lines up). I found a third, much rarer value which was again separated by another 17 ms, further backing up this idea of the task manager waiting 0-2 frames before firing the remote.

This behavior is loosely documented here Task Scheduler | Documentation - Roblox Creator Hub

Replication Send Jobs:
Outgoing property updates and event firings are sent. Does not happen every frame.

I find this total lack of control over this behavior to be frustrating, because I am only trying to send a signal once a second, so being consistently throttled for such a low network load is insulting.

2 Likes

Because ROBLOX decided that’s how it wants to do things :slight_smile:

But also, network comms are unreliable anyways, and you shouldn’t rely on remotes being sent exactly on time, since they won’t be received on time in any case.

2 Likes

Well, packet loss and inconsistencies stemming from that are understandable. But, these shifts caused by the task scheduler changing its mind about when it wants to fire the remote is just unnecessary flux and I want to eliminate it. This is ridiculous.

1 Like

It’s because Roblox enforces a reliable-ordered communication channel, i.e. they make sure that all messages are received in the correct order.

This necessitates waiting some amount of time before firing the event handler, because you need to know that the other side knows that you’ve received the message and that there weren’t any events that should fire first but arrived later.

Roblox chose to do this synchronously with Heartbeat.

I mean, it makes sense. You have some point in time every frame where all Lua tasks are handled, which makes a lot of things a lot less complicated. However, this is really bad for anything where timing is critical, such as replicating movement updates (or worse, physics that require interaction between parts simulated locally on the clients).

I’ve written a thread that highlights the issue, and there’s a feature request that aims to alleviate these problems. In timing-critical netcode, you also necessarily lose the ability to send information reliably, i.e. you may receive your packets out of order or not at all, so please don’t get spooked by the term “unreliable communication”.

1 Like