Modules: Improve timer accuracy (#7987)

The bug occurs when 'callback' re-registers itself to a point
in the future and the execution time in non-negligible:
'now' refers to time BEFORE callback was executed and is used
to calculate 'next_period'.
We must get the actual current time when calculating 'next_period'
This commit is contained in:
guybe7 2020-11-02 17:18:42 +01:00 committed by GitHub
parent b5f3996250
commit 1a91a2700b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5442,7 +5442,10 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client
raxRemove(Timers,(unsigned char*)ri.key,ri.key_len,NULL);
zfree(timer);
} else {
next_period = (expiretime-now)/1000; /* Scale to milliseconds. */
/* We call ustime() again instead of using the cached 'now' so that
* 'next_period' isn't affected by the time it took to execute
* previous calls to 'callback. */
next_period = (expiretime-ustime())/1000; /* Scale to milliseconds. */
break;
}
}
@ -5455,7 +5458,16 @@ int moduleTimerHandler(struct aeEventLoop *eventLoop, long long id, void *client
/* Create a new timer that will fire after `period` milliseconds, and will call
* the specified function using `data` as argument. The returned timer ID can be
* used to get information from the timer or to stop it before it fires. */
* used to get information from the timer or to stop it before it fires.
* Note that for the common use case of a repeating timer (Re-registration
* of the timer inside the RedisModuleTimerProc callback) it matters when
* this API is called:
* If it is called at the beginning of 'callback' it means
* the event will triggered every 'period'.
* If it is called at the end of 'callback' it means
* there will 'period' milliseconds gaps between events.
* (If the time it takes to execute 'callback' is negligible the two
* statements above mean the same) */
RedisModuleTimerID RM_CreateTimer(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data) {
RedisModuleTimer *timer = zmalloc(sizeof(*timer));
timer->module = ctx->module;