From 5c4495610043bcdb8a2a7dddfcce9d834b649459 Mon Sep 17 00:00:00 2001 From: "Brandon Waterloo [MSFT]" <36966225+bwateratmsft@users.noreply.github.com> Date: Wed, 9 Nov 2022 14:21:31 -0500 Subject: [PATCH 1/4] Copy upstream changes --- .../docker/clients/DockerClientBase/DockerClientBase.ts | 4 ++-- src/runtimes/docker/contracts/ContainerClient.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtimes/docker/clients/DockerClientBase/DockerClientBase.ts b/src/runtimes/docker/clients/DockerClientBase/DockerClientBase.ts index 8ebf4c2f9b..2cc650b129 100644 --- a/src/runtimes/docker/clients/DockerClientBase/DockerClientBase.ts +++ b/src/runtimes/docker/clients/DockerClientBase/DockerClientBase.ts @@ -257,8 +257,8 @@ export abstract class DockerClientBase extends ConfigurableClient implements ICo ): CommandLineArgs { return composeArgs( withArg('events'), - withNamedArg('--since', options.since), - withNamedArg('--until', options.until), + withNamedArg('--since', options.since?.toString(), { shouldQuote: !(typeof options.since === 'number') }), // If it's numeric it should not be quoted + withNamedArg('--until', options.until?.toString(), { shouldQuote: !(typeof options.until === 'number') }), // If it's numeric it should not be quoted withDockerLabelFilterArgs(options.labels), withNamedArg('--filter', options.types?.map((type) => `type=${type}`)), withNamedArg('--filter', options.events?.map((event) => `event=${event}`)), diff --git a/src/runtimes/docker/contracts/ContainerClient.ts b/src/runtimes/docker/contracts/ContainerClient.ts index 1221d07fca..432bdad6e5 100644 --- a/src/runtimes/docker/contracts/ContainerClient.ts +++ b/src/runtimes/docker/contracts/ContainerClient.ts @@ -174,11 +174,11 @@ export type EventStreamCommandOptions = CommonCommandOptions & { /** * Return events since a given timestamp */ - since?: string; + since?: string | number; /** * Only stream events until a given timestamp */ - until?: string; + until?: string | number; /** * Only listen for events affecting these object types */ From 1d779e67b53bd232ee289c93641751e141f4031f Mon Sep 17 00:00:00 2001 From: "Brandon Waterloo [MSFT]" <36966225+bwateratmsft@users.noreply.github.com> Date: Wed, 9 Nov 2022 14:24:00 -0500 Subject: [PATCH 2/4] Restart the event listener every 5 minutes --- src/tree/RefreshManager.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/tree/RefreshManager.ts b/src/tree/RefreshManager.ts index 67d4165e61..386515a0fe 100644 --- a/src/tree/RefreshManager.ts +++ b/src/tree/RefreshManager.ts @@ -14,6 +14,7 @@ import { AllTreePrefixes, TreePrefix } from './TreePrefix'; const pollingIntervalMs = 60 * 1000; // One minute const eventListenerTries = 3; // The event listener will try at most 3 times to connect for events +const eventListenerLifetimeSeconds = 60 * 5; // Five minutes const debounceDelayMs = 500; // Refreshes rapidly initiated for the same tree view will be debounced to occur 500ms after the last initiation type RefreshTarget = AzExtTreeItem | TreePrefix; @@ -108,12 +109,18 @@ export class RefreshManager extends vscode.Disposable { const eventActionsToWatch: EventAction[] = Array.from(new Set([...ContainerEventActions, ...ImageEventActions, ...NetworkEventActions, ...VolumeEventActions])); // Try at most `eventListenerTries` times to (re)connect to the event stream - for (let i = 0; i < eventListenerTries; i++) { + let errorCount = 0; + let eventsSinceTimestamp = Math.round(Date.now() / 1000); + while (errorCount < eventListenerTries) { + const eventsUntilTimestamp = eventsSinceTimestamp + eventListenerLifetimeSeconds; + try { const eventGenerator = ext.streamWithDefaultShell(client => client.getEventStream({ types: eventTypesToWatch, events: eventActionsToWatch, + since: eventsSinceTimestamp, + until: eventsUntilTimestamp, }), { cancellationToken: this.cts.token, @@ -145,7 +152,7 @@ export class RefreshManager extends vscode.Disposable { if (isCancellationError(err) || error.isUserCancelledError) { // Cancelled, so don't try again and don't rethrow--this is a normal termination pathway return; - } else if (i < eventListenerTries - 1) { + } else if (++errorCount < eventListenerTries) { // Still in the retry loop continue; } else { @@ -156,7 +163,13 @@ export class RefreshManager extends vscode.Disposable { throw error; } + } finally { + // Move the next start timestamp to the current end timestamp + eventsSinceTimestamp = eventsUntilTimestamp; } + + // If the event generator terminates on its expected lifecycle it will exit without an error + // Continue the loop as normal, starting the next event stream at the previous stop time } }); From fc7ad893b75782019e1bce906d14843c3eff6afc Mon Sep 17 00:00:00 2001 From: "Brandon Waterloo [MSFT]" <36966225+bwateratmsft@users.noreply.github.com> Date: Thu, 10 Nov 2022 12:04:45 -0500 Subject: [PATCH 3/4] Karol's feedback --- src/tree/RefreshManager.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tree/RefreshManager.ts b/src/tree/RefreshManager.ts index 386515a0fe..305548c538 100644 --- a/src/tree/RefreshManager.ts +++ b/src/tree/RefreshManager.ts @@ -170,6 +170,8 @@ export class RefreshManager extends vscode.Disposable { // If the event generator terminates on its expected lifecycle it will exit without an error // Continue the loop as normal, starting the next event stream at the previous stop time + // We intentionally do not reset the `errorCount`, so that at most 3 failures occur before + // giving up, regardless of whether or not they are consecutive. } }); From 76c6f09c69ea7ef93f62b8e0a69265b4d12b7817 Mon Sep 17 00:00:00 2001 From: "Brandon Waterloo [MSFT]" <36966225+bwateratmsft@users.noreply.github.com> Date: Thu, 10 Nov 2022 12:19:21 -0500 Subject: [PATCH 4/4] Spare newline --- src/tree/RefreshManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tree/RefreshManager.ts b/src/tree/RefreshManager.ts index 305548c538..cbd661555c 100644 --- a/src/tree/RefreshManager.ts +++ b/src/tree/RefreshManager.ts @@ -174,7 +174,6 @@ export class RefreshManager extends vscode.Disposable { // giving up, regardless of whether or not they are consecutive. } }); - } private setupRefreshOnConfigurationChange(): void {