Grakkit's JavaScript ticker (chain) can fail and does not resume
MercerK opened this issue ยท 1 comments
I ran into an issue with setTimeout
/ setImmediate
not working. After a lot of investigation, I narrowed it down to chain and instance.tick.
When the bug occurs, session.task.tick will stop accumulating and will always be stuck. When that happens, the JS's ticker will not trigger again until you do a reboot of the server.
My theory is that this may be due to a race condition between the Java/JS/Graal layers. I'm thinking that if a tick takes longer than a regular Java tick, it tries to call JavaScript's tick and nothing happens. When nothing happens, well, it gets released. Since it is released, it does not get readded (as it wasn't called/executed), thus, It doesn't know to tick it again. This seems like a major flaw.
I added a temporary hook in the library for troubleshooting
let thisNext
chain(void 0, (none, next) => {
thisNext = next
....
}
export const restartTick = () => {
Grakkit.push(thisNext)
}
and was able to trigger restartTick
by a command. When that happened, the ticker immediately start ticking again. However, that isn't a valid solution.
Since Grakkit leverages runTaskLater
, it makes an attempt to call the function on that task. If that task fails, then the ticker fails hard. This doesn't seem to be a fault on the JavaScript side and I don't see a bug on the Grakkit side. It seems more of an issue between the two layers. Assuming that is the case, we should document this and build around the bug to avoid it as much as possible.
However, for this scenario, we may be able to mitigate it by:
- Add a new method with Instance/GrakkitApi to register a ticker function. This is permanent and gets added to the tick.
- Update Stdlib to register a ticker, versus leveraging
Grakkit.push
.