history - use Limiter for storing models on shutdown

This commit is contained in:
Benjamin Pasero 2022-03-18 11:28:13 +01:00
parent 8d990b03ae
commit 0b662296d5
No known key found for this signature in database
GPG key ID: E6380CC4C8219E65
6 changed files with 31 additions and 6 deletions

View file

@ -319,7 +319,7 @@ export class NativeWindow extends Disposable {
// Lifecycle
this._register(this.lifecycleService.onBeforeShutdown(e => this.onBeforeShutdown(e)));
this._register(this.lifecycleService.onBeforeShutdownError(e => this.onBeforeShutdownError(e)));
this._register(this.lifecycleService.onWillShutdown((e) => this.onWillShutdown(e)));
this._register(this.lifecycleService.onWillShutdown(e => this.onWillShutdown(e)));
}
private onBeforeShutdown({ reason }: BeforeShutdownEvent): void {

View file

@ -11,6 +11,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IDisposable } from 'vs/base/common/lifecycle';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
import { IStorageService, WillSaveStateReason } from 'vs/platform/storage/common/storage';
import { CancellationToken } from 'vs/base/common/cancellation';
export class BrowserLifecycleService extends AbstractLifecycleService {
@ -167,6 +168,7 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
const logService = this.logService;
this._onWillShutdown.fire({
reason: ShutdownReason.QUIT,
token: CancellationToken.None, // Unsupported in web
join(promise, id) {
logService.error(`[lifecycle] Long running operations during shutdown are unsupported in the web (id: ${id})`);
},

View file

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
@ -79,6 +80,12 @@ export interface WillShutdownEvent {
*/
readonly reason: ShutdownReason;
/**
* A token that will signal cancellation when the
* shutdown was forced by the user.
*/
readonly token: CancellationToken;
/**
* Allows to join the shutdown. The promise can be a long running operation but it
* will block the application from closing.

View file

@ -160,6 +160,7 @@ export class NativeLifecycleService extends AbstractLifecycleService {
this._onWillShutdown.fire({
reason,
token: cts.token,
join(promise, id) {
joiners.push(promise);

View file

@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Limiter } from 'vs/base/common/async';
import { Event } from 'vs/base/common/event';
import { ILifecycleService, WillShutdownEvent } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IFileService } from 'vs/platform/files/common/files';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
@ -39,15 +41,26 @@ export class NativeWorkingCopyHistoryService extends WorkingCopyHistoryService {
private onWillShutdown(e: WillShutdownEvent): void {
// Prolong shutdown for orderly model shutdown
e.join((async () => {
e.join((() => {
const limiter = new Limiter(20); // prevent too many IO-ops running in parallel
const models = Array.from(this.models.values());
for (const model of models) {
try {
await model.store();
} catch (error) {
this.logService.trace(error);
if (e.token.isCancellationRequested) {
limiter.dispose();
break;
}
limiter.queue(async () => {
try {
await model.store();
} catch (error) {
this.logService.trace(error);
}
});
}
return Event.toPromise(limiter.onFinished);
})(), 'join.workingCopyHistory');
}
}

View file

@ -1218,6 +1218,7 @@ export class TestLifecycleService implements ILifecycleService {
this.shutdownJoiners.push(p);
},
force: () => { /* No-Op in tests */ },
token: CancellationToken.None,
reason
});
}
@ -1251,6 +1252,7 @@ export class TestWillShutdownEvent implements WillShutdownEvent {
value: Promise<void>[] = [];
reason = ShutdownReason.CLOSE;
token = CancellationToken.None;
join(promise: Promise<void>, id: string): void {
this.value.push(promise);