mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Add timeouts to prevent ActiveDoc bad state during shutdown.
Summary: Add two shutdown-related timeouts. 1. One is to limit the duration of any work that happens once shutdown begins. In particular, waiting for an update to current time could block indefinitely if the data engine is unresponsive. Such awaits are now limited to 5 seconds. 2. The other is to allow documents to get shutdown for inactivity even when some work takes forever. Certain work (e.g. applying user actions) generally prevents a document from shutting down while it's pending. This prevention is now limited to 5 minutes. Shutting down a doc while something is pending may break some assumptions, and lead to errors. The timeout is long to let us assume that the work is stuck, and that errors are better than waiting forever. Other changes: - Periodic ActiveDoc work (intervals) is now started when a doc finishes loading rather than in the constructor. The difference only showed up in tests which makes the intervals much shorter. - Move timeoutReached() utility function to gutil, and use it for isLongerThan(), since they are basically identical. Also makes sure that the timer in these is cleared in all cases. - Remove duplicate waitForIt implementation (previously had a copy in both test/server and core/test/server). - Change testUtil.captureLog to pass messages to its callback, to allow asserts on messages within the callback. Test Plan: Added new unittests for the new shutdowns, including a replication of a bad state that was possible during shutdown. Reviewers: paulfitz Reviewed By: paulfitz Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D4040
This commit is contained in:
@@ -124,7 +124,9 @@ export function setTmpLogLevel(level: string, optCaptureFunc?: (level: string, m
|
||||
* captures those at minLevel and higher. Returns a promise for the array of "level: message"
|
||||
* strings. These may be tested using testUtils.assertMatchArray(). Callback may return a promise.
|
||||
*/
|
||||
export async function captureLog(minLevel: string, callback: () => void|Promise<void>): Promise<string[]> {
|
||||
export async function captureLog(
|
||||
minLevel: string, callback: (messages: string[]) => void|Promise<void>
|
||||
): Promise<string[]> {
|
||||
const messages: string[] = [];
|
||||
const prevLogLevel = log.transports.file.level;
|
||||
const name = _.uniqueId('CaptureLog');
|
||||
@@ -140,7 +142,7 @@ export async function captureLog(minLevel: string, callback: () => void|Promise<
|
||||
}
|
||||
log.add(CaptureTransport as any, { captureFunc: capture, name }); // types are off.
|
||||
try {
|
||||
await callback();
|
||||
await callback(messages);
|
||||
} finally {
|
||||
log.remove(name);
|
||||
log.transports.file.level = prevLogLevel;
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as bluebird from 'bluebird';
|
||||
/**
|
||||
* Wait some time for a check to pass. Allow a pause between checks.
|
||||
*/
|
||||
export async function waitForIt(check: () => Promise<void>, maxWaitMs: number,
|
||||
export async function waitForIt(check: () => Promise<void>|void, maxWaitMs: number,
|
||||
stepWaitMs: number = 1000) {
|
||||
const start = Date.now();
|
||||
for (;;) {
|
||||
|
||||
Reference in New Issue
Block a user