Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ const config: CodegenConfig = {
URL: 'URL',
Port: 'number',
UUID: 'string',
BigInt: 'number',
},
scalarSchemas: {
URL: 'z.instanceof(URL)',
Long: 'z.number()',
JSON: 'z.record(z.string(), z.any())',
Port: 'z.number()',
UUID: 'z.string()',
BigInt: 'z.number()',
},
},
generates: {
Expand Down
2 changes: 1 addition & 1 deletion api/dev/configs/api.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "4.22.1",
"version": "4.22.2",
"extraOrigins": [],
"sandbox": true,
"ssoSubIds": [],
Expand Down
4 changes: 2 additions & 2 deletions api/generated-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,8 @@ type DockerContainer implements Node {
created: Int!
ports: [ContainerPort!]!

"""Total size of all the files in the container"""
sizeRootFs: Int
"""Total size of all files in the container (in bytes)"""
sizeRootFs: BigInt
Comment on lines +1096 to +1097
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Schema change to BigInt matches the model.

Alignment with the model is correct. Ensure client codegen maps BigInt consistently (string or bigint) to prevent runtime mismatches.

Run this to sanity-check mappings and usages:


🏁 Script executed:

#!/bin/bash
# Locate codegen config and BigInt scalar mappings/usages
fd -a -H 'codegen*' .
rg -nP --glob '!**/node_modules/**' 'BigInt' -C2
rg -nP --glob '!**/node_modules/**' 'sizeRootFs' -C2

Length of output: 430


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Listing codegen files (relative paths):"
fd -a -H 'codegen.ts' || true

echo
echo "----- Show head of api/codegen.ts -----"
sed -n '1,300p' api/codegen.ts || true
echo
echo "----- Show head of packages/unraid-api-plugin-connect/codegen.ts -----"
sed -n '1,300p' packages/unraid-api-plugin-connect/codegen.ts || true
echo
echo "----- Show head of web/codegen.ts -----"
sed -n '1,300p' web/codegen.ts || true

echo
echo "----- Repo-wide search for 'BigInt' (including ignored files) -----"
rg -nP -uu 'BigInt' -C3 || true

echo
echo "----- Repo-wide search for 'sizeRootFs' (including ignored files) -----"
rg -nP -uu 'sizeRootFs' -C3 || true

echo
echo "----- Search for GraphQL scalar mappings (scalars:) -----"
rg -nP -uu "scalars\s*:" -C3 || true

echo
echo "----- Search for explicit 'scalar BigInt' GraphQL definition -----"
rg -nP -uu "scalar\s+BigInt" -C3 || true

echo
echo "----- Search for BigInt mapping patterns (e.g. BigInt: 'string' or BigInt: 'bigint') -----"
rg -nP -uu "BigInt\s*:\s*(['\"][a-zA-Z_]+['\"]|[a-zA-Z_]+)" -C3 || true

Length of output: 61970


Add explicit BigInt scalar mapping and regenerate client types

  • Schema change to BigInt matches server use of GraphQLBigInt.
  • Problem: codegen configs do not map BigInt — update needed in api/codegen.ts, packages/unraid-api-plugin-connect/codegen.ts, web/codegen.ts. Current generated outputs show BigInt defaulting to any or (in some client files) remaining as Int (see api/src/unraid-api/cli/generated/graphql.ts, web/composables/gql/graphql.ts, web/src/composables/gql/graphql.ts).
  • Action: add a BigInt scalar mapping (choose "string" or "bigint") and scalarSchemas where applicable, run graphql-codegen to regenerate client types, and verify/adjust server model TS property types to match the chosen runtime representation (e.g., api/src/unraid-api/graph/resolvers/*/— memory.model.ts, docker.model.ts, array.model.ts).
🤖 Prompt for AI Agents
In api/generated-schema.graphql around lines 1096-1097, BigInt scalar is added
but codegen configs lack an explicit mapping which causes generated clients to
default to any/Int; update api/codegen.ts,
packages/unraid-api-plugin-connect/codegen.ts, and web/codegen.ts to add a
BigInt scalar mapping (pick either "string" or "bigint") and include
scalarSchemas where required, then run graphql-codegen to regenerate client
types (verify api/src/unraid-api/cli/generated/graphql.ts,
web/composables/gql/graphql.ts, web/src/composables/gql/graphql.ts reflect the
mapping), and finally adjust server model TypeScript property types to match the
chosen runtime representation in files like
api/src/unraid-api/graph/resolvers/*/— memory.model.ts, docker.model.ts,
array.model.ts before committing.

labels: JSON
state: ContainerState!
status: String!
Expand Down
6 changes: 3 additions & 3 deletions api/src/unraid-api/cli/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type Scalars = {
Int: { input: number; output: number; }
Float: { input: number; output: number; }
/** The `BigInt` scalar type represents non-fractional signed whole numeric values. */
BigInt: { input: any; output: any; }
BigInt: { input: number; output: number; }
/** A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. */
DateTime: { input: string; output: string; }
/** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
Expand Down Expand Up @@ -711,8 +711,8 @@ export type DockerContainer = Node & {
names: Array<Scalars['String']['output']>;
networkSettings?: Maybe<Scalars['JSON']['output']>;
ports: Array<ContainerPort>;
/** Total size of all the files in the container */
sizeRootFs?: Maybe<Scalars['Int']['output']>;
/** Total size of all files in the container (in bytes) */
sizeRootFs?: Maybe<Scalars['BigInt']['output']>;
state: ContainerState;
status: Scalars['String']['output'];
};
Expand Down
7 changes: 5 additions & 2 deletions api/src/unraid-api/graph/resolvers/docker/docker.model.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Field, ID, Int, ObjectType, registerEnumType } from '@nestjs/graphql';

import { Node } from '@unraid/shared/graphql.model.js';
import { GraphQLJSON, GraphQLPort } from 'graphql-scalars';
import { GraphQLBigInt, GraphQLJSON, GraphQLPort } from 'graphql-scalars';

export enum ContainerPortType {
TCP = 'TCP',
Expand Down Expand Up @@ -89,7 +89,10 @@ export class DockerContainer extends Node {
@Field(() => [ContainerPort])
ports!: ContainerPort[];

@Field(() => Int, { nullable: true, description: 'Total size of all the files in the container' })
@Field(() => GraphQLBigInt, {
nullable: true,
description: 'Total size of all files in the container (in bytes)',
})
sizeRootFs?: number;
Comment on lines +92 to 96
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Align TS type with GraphQLBigInt (use bigint, not number).

GraphQLBigInt uses JS BigInt at runtime. Keeping the property typed as number risks precision loss and serialization mismatches for large values.

Apply this minimal change:

-    })
-    sizeRootFs?: number;
+    })
+    sizeRootFs?: bigint;

Follow‑up: ensure the resolver populates this field with a BigInt, not a number (see service comment).
Reference: GraphQLBigInt uses native JS BigInt. (the-guild.dev)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Field(() => GraphQLBigInt, {
nullable: true,
description: 'Total size of all files in the container (in bytes)',
})
sizeRootFs?: number;
@Field(() => GraphQLBigInt, {
nullable: true,
description: 'Total size of all files in the container (in bytes)',
})
sizeRootFs?: bigint;
🤖 Prompt for AI Agents
In api/src/unraid-api/graph/resolvers/docker/docker.model.ts around lines 92-96,
the GraphQLBigInt-decorated field sizeRootFs is currently typed as number which
can cause precision loss and mismatch; change the TypeScript type to bigint
(sizeRootFs?: bigint) and update any callers/resolvers to produce/return a
native BigInt value (e.g., BigInt(...)) so the resolver serializes correctly
with GraphQLBigInt.


@Field(() => GraphQLJSON, { nullable: true })
Expand Down
80 changes: 78 additions & 2 deletions api/src/unraid-api/graph/resolvers/docker/docker.resolver.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import { ContainerState, DockerContainer } from '@app/unraid-api/graph/resolvers
import { DockerResolver } from '@app/unraid-api/graph/resolvers/docker/docker.resolver.js';
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.js';
import { GraphQLFieldHelper } from '@app/unraid-api/utils/graphql-field-helper.js';

vi.mock('@app/unraid-api/utils/graphql-field-helper.js', () => ({
GraphQLFieldHelper: {
isFieldRequested: vi.fn(),
},
}));

describe('DockerResolver', () => {
let resolver: DockerResolver;
Expand Down Expand Up @@ -41,6 +48,9 @@ describe('DockerResolver', () => {

resolver = module.get<DockerResolver>(DockerResolver);
dockerService = module.get<DockerService>(DockerService);

// Reset mocks before each test
vi.clearAllMocks();
});

it('should be defined', () => {
Expand Down Expand Up @@ -80,9 +90,75 @@ describe('DockerResolver', () => {
},
];
vi.mocked(dockerService.getContainers).mockResolvedValue(mockContainers);
vi.mocked(GraphQLFieldHelper.isFieldRequested).mockReturnValue(false);

const mockInfo = {} as any;

const result = await resolver.containers(false, mockInfo);
expect(result).toEqual(mockContainers);
expect(GraphQLFieldHelper.isFieldRequested).toHaveBeenCalledWith(mockInfo, 'sizeRootFs');
expect(dockerService.getContainers).toHaveBeenCalledWith({ skipCache: false, size: false });
});

it('should request size when sizeRootFs field is requested', async () => {
const mockContainers: DockerContainer[] = [
{
id: '1',
autoStart: false,
command: 'test',
names: ['test-container'],
created: 1234567890,
image: 'test-image',
imageId: 'test-image-id',
ports: [],
sizeRootFs: 1024000,
state: ContainerState.EXITED,
status: 'Exited',
},
];
vi.mocked(dockerService.getContainers).mockResolvedValue(mockContainers);
vi.mocked(GraphQLFieldHelper.isFieldRequested).mockReturnValue(true);

const result = await resolver.containers(false);
const mockInfo = {} as any;

const result = await resolver.containers(false, mockInfo);
expect(result).toEqual(mockContainers);
expect(dockerService.getContainers).toHaveBeenCalledWith({ skipCache: false });
expect(GraphQLFieldHelper.isFieldRequested).toHaveBeenCalledWith(mockInfo, 'sizeRootFs');
expect(dockerService.getContainers).toHaveBeenCalledWith({ skipCache: false, size: true });
});

it('should request size when GraphQLFieldHelper indicates sizeRootFs is requested', async () => {
const mockContainers: DockerContainer[] = [];
vi.mocked(dockerService.getContainers).mockResolvedValue(mockContainers);
vi.mocked(GraphQLFieldHelper.isFieldRequested).mockReturnValue(true);

const mockInfo = {} as any;

await resolver.containers(false, mockInfo);
expect(GraphQLFieldHelper.isFieldRequested).toHaveBeenCalledWith(mockInfo, 'sizeRootFs');
expect(dockerService.getContainers).toHaveBeenCalledWith({ skipCache: false, size: true });
});

it('should not request size when GraphQLFieldHelper indicates sizeRootFs is not requested', async () => {
const mockContainers: DockerContainer[] = [];
vi.mocked(dockerService.getContainers).mockResolvedValue(mockContainers);
vi.mocked(GraphQLFieldHelper.isFieldRequested).mockReturnValue(false);

const mockInfo = {} as any;

await resolver.containers(false, mockInfo);
expect(GraphQLFieldHelper.isFieldRequested).toHaveBeenCalledWith(mockInfo, 'sizeRootFs');
expect(dockerService.getContainers).toHaveBeenCalledWith({ skipCache: false, size: false });
});

it('should handle skipCache parameter', async () => {
const mockContainers: DockerContainer[] = [];
vi.mocked(dockerService.getContainers).mockResolvedValue(mockContainers);
vi.mocked(GraphQLFieldHelper.isFieldRequested).mockReturnValue(false);

const mockInfo = {} as any;

await resolver.containers(true, mockInfo);
expect(dockerService.getContainers).toHaveBeenCalledWith({ skipCache: true, size: false });
});
});
10 changes: 7 additions & 3 deletions api/src/unraid-api/graph/resolvers/docker/docker.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Args, Mutation, Query, ResolveField, Resolver } from '@nestjs/graphql';
import { Args, Info, Mutation, Query, ResolveField, Resolver } from '@nestjs/graphql';

import type { GraphQLResolveInfo } from 'graphql';
import { AuthAction, Resource } from '@unraid/shared/graphql.model.js';
import { UsePermissions } from '@unraid/shared/use-permissions.directive.js';

Expand All @@ -15,6 +16,7 @@ import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.ser
import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.js';
import { DEFAULT_ORGANIZER_ROOT_ID } from '@app/unraid-api/organizer/organizer.js';
import { ResolvedOrganizerV1 } from '@app/unraid-api/organizer/organizer.model.js';
import { GraphQLFieldHelper } from '@app/unraid-api/utils/graphql-field-helper.js';

@Resolver(() => Docker)
export class DockerResolver {
Expand All @@ -41,9 +43,11 @@ export class DockerResolver {
})
@ResolveField(() => [DockerContainer])
public async containers(
@Args('skipCache', { defaultValue: false, type: () => Boolean }) skipCache: boolean
@Args('skipCache', { defaultValue: false, type: () => Boolean }) skipCache: boolean,
@Info() info: GraphQLResolveInfo
) {
return this.dockerService.getContainers({ skipCache });
const requestsSize = GraphQLFieldHelper.isFieldRequested(info, 'sizeRootFs');
return this.dockerService.getContainers({ skipCache, size: requestsSize });
}

@UsePermissions({
Expand Down
61 changes: 60 additions & 1 deletion api/src/unraid-api/graph/resolvers/docker/docker.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,65 @@ describe('DockerService', () => {
expect(service).toBeDefined();
});

it('should use separate cache keys for containers with and without size', async () => {
const mockContainersWithoutSize = [
{
Id: 'abc123',
Names: ['/test-container'],
Image: 'test-image',
ImageID: 'test-image-id',
Command: 'test',
Created: 1234567890,
State: 'exited',
Status: 'Exited',
Ports: [],
Labels: {},
HostConfig: { NetworkMode: 'bridge' },
NetworkSettings: {},
Mounts: [],
},
];

const mockContainersWithSize = [
{
Id: 'abc123',
Names: ['/test-container'],
Image: 'test-image',
ImageID: 'test-image-id',
Command: 'test',
Created: 1234567890,
State: 'exited',
Status: 'Exited',
Ports: [],
Labels: {},
HostConfig: { NetworkMode: 'bridge' },
NetworkSettings: {},
Mounts: [],
SizeRootFs: 1024000,
},
];

// First call without size
mockListContainers.mockResolvedValue(mockContainersWithoutSize);
mockCacheManager.get.mockResolvedValue(undefined);

await service.getContainers({ size: false });

expect(mockCacheManager.set).toHaveBeenCalledWith('docker_containers', expect.any(Array), 60000);

// Second call with size
mockListContainers.mockResolvedValue(mockContainersWithSize);
mockCacheManager.get.mockResolvedValue(undefined);

await service.getContainers({ size: true });

expect(mockCacheManager.set).toHaveBeenCalledWith(
'docker_containers_with_size',
expect.any(Array),
60000
);
});

it('should get containers', async () => {
const mockContainers = [
{
Expand Down Expand Up @@ -159,7 +218,7 @@ describe('DockerService', () => {

expect(mockListContainers).toHaveBeenCalledWith({
all: true,
size: true,
size: false,
});
expect(mockCacheManager.set).toHaveBeenCalled(); // Ensure cache is set
});
Expand Down
40 changes: 22 additions & 18 deletions api/src/unraid-api/graph/resolvers/docker/docker.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class DockerService {
private readonly logger = new Logger(DockerService.name);

public static readonly CONTAINER_CACHE_KEY = 'docker_containers';
public static readonly CONTAINER_WITH_SIZE_CACHE_KEY = 'docker_containers_with_size';
public static readonly NETWORK_CACHE_KEY = 'docker_networks';
public static readonly CACHE_TTL_SECONDS = 60; // Cache for 60 seconds

Expand Down Expand Up @@ -71,6 +72,8 @@ export class DockerService {
}

public transformContainer(container: Docker.ContainerInfo): DockerContainer {
const sizeValue = (container as Docker.ContainerInfo & { SizeRootFs?: number }).SizeRootFs;

Comment on lines +75 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Avoid cast and prepare value for BigInt.

Current cast to add SizeRootFs is brittle. Prefer a small helper type or a type guard, and coerce to BigInt at the source.

Option A (local helper type):

+type ContainerInfoMaybeSized = Docker.ContainerInfo & { SizeRootFs?: number };
-const sizeValue = (container as Docker.ContainerInfo & { SizeRootFs?: number }).SizeRootFs;
+const sizeValue = (container as ContainerInfoMaybeSized).SizeRootFs;

Then set the field as BigInt (see next comment).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const sizeValue = (container as Docker.ContainerInfo & { SizeRootFs?: number }).SizeRootFs;
type ContainerInfoMaybeSized = Docker.ContainerInfo & { SizeRootFs?: number };
const sizeValue = (container as ContainerInfoMaybeSized).SizeRootFs;
🤖 Prompt for AI Agents
In api/src/unraid-api/graph/resolvers/docker/docker.service.ts around lines
75-76, avoid the brittle inline cast for SizeRootFs; introduce a small local
helper type or a type guard that safely narrows Docker.ContainerInfo to a shape
that includes SizeRootFs, then read and coerce the value to a BigInt at the
source (e.g., check for undefined/null and numeric/string input, convert via
BigInt) and assign the field as a BigInt so downstream code receives a
strongly-typed BigInt instead of relying on a fragile cast.

const transformed: DockerContainer = {
id: container.Id,
names: container.Names,
Expand All @@ -86,7 +89,7 @@ export class DockerService {
ContainerPortType[port.Type.toUpperCase() as keyof typeof ContainerPortType] ||
ContainerPortType.TCP,
})),
sizeRootFs: undefined,
sizeRootFs: sizeValue,
labels: container.Labels ?? {},
Comment on lines +92 to 93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Populate GraphQLBigInt with a JS BigInt.

Return a BigInt to match the scalar and avoid precision issues.

Apply this change:

-            sizeRootFs: sizeValue,
+            sizeRootFs: sizeValue !== undefined ? BigInt(sizeValue) : undefined,

Reference: GraphQLBigInt expects native BigInt. (the-guild.dev)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sizeRootFs: sizeValue,
labels: container.Labels ?? {},
sizeRootFs: sizeValue !== undefined ? BigInt(sizeValue) : undefined,
labels: container.Labels ?? {},
🤖 Prompt for AI Agents
In api/src/unraid-api/graph/resolvers/docker/docker.service.ts around lines
92-93, sizeRootFs is being set to sizeValue (a JS number) but the GraphQLBigInt
scalar expects a native BigInt; change the assignment to return a BigInt
instead, e.g. set sizeRootFs to sizeValue != null ? BigInt(sizeValue) : null so
you return a BigInt when a value exists and preserve null/undefined otherwise.

state:
typeof container.State === 'string'
Expand All @@ -109,21 +112,23 @@ export class DockerService {
{
skipCache = false,
all = true,
size = true,
size = false,
...listOptions
}: Partial<ContainerListingOptions> = { skipCache: false }
): Promise<DockerContainer[]> {
const cacheKey = size
? DockerService.CONTAINER_WITH_SIZE_CACHE_KEY
: DockerService.CONTAINER_CACHE_KEY;

if (!skipCache) {
const cachedContainers = await this.cacheManager.get<DockerContainer[]>(
DockerService.CONTAINER_CACHE_KEY
);
const cachedContainers = await this.cacheManager.get<DockerContainer[]>(cacheKey);
if (cachedContainers) {
this.logger.debug('Using docker container cache');
this.logger.debug(`Using docker container cache (${size ? 'with' : 'without'} size)`);
return cachedContainers;
}
}

this.logger.debug('Updating docker container cache');
this.logger.debug(`Updating docker container cache (${size ? 'with' : 'without'} size)`);
const rawContainers =
(await this.client
.listContainers({
Expand All @@ -136,11 +141,7 @@ export class DockerService {
this.autoStarts = await this.getAutoStarts();
const containers = rawContainers.map((container) => this.transformContainer(container));

await this.cacheManager.set(
DockerService.CONTAINER_CACHE_KEY,
containers,
DockerService.CACHE_TTL_SECONDS * 1000
);
await this.cacheManager.set(cacheKey, containers, DockerService.CACHE_TTL_SECONDS * 1000);
return containers;
}

Expand Down Expand Up @@ -191,15 +192,18 @@ export class DockerService {
}

public async clearContainerCache(): Promise<void> {
await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY);
this.logger.debug('Invalidated container cache due to external event.');
await Promise.all([
this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY),
this.cacheManager.del(DockerService.CONTAINER_WITH_SIZE_CACHE_KEY),
]);
this.logger.debug('Invalidated container caches due to external event.');
}

public async start(id: string): Promise<DockerContainer> {
const container = this.client.getContainer(id);
await container.start();
await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY);
this.logger.debug(`Invalidated container cache after starting ${id}`);
await this.clearContainerCache();
this.logger.debug(`Invalidated container caches after starting ${id}`);
const containers = await this.getContainers({ skipCache: true });
const updatedContainer = containers.find((c) => c.id === id);
if (!updatedContainer) {
Expand All @@ -213,8 +217,8 @@ export class DockerService {
public async stop(id: string): Promise<DockerContainer> {
const container = this.client.getContainer(id);
await container.stop({ t: 10 });
await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY);
this.logger.debug(`Invalidated container cache after stopping ${id}`);
await this.clearContainerCache();
this.logger.debug(`Invalidated container caches after stopping ${id}`);

let containers = await this.getContainers({ skipCache: true });
let updatedContainer: DockerContainer | undefined;
Expand Down
Loading
Loading