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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,19 +90,12 @@ public actor ContainersService {
)
)
results[config.id] = state
let plugin = runtimePlugins.first { $0.name == config.runtimeHandler }
guard let plugin else {
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: more concise here and on L155:

guard runtimePlugins.contains(where:{ $0.name == config.runtimeHandler })else{...}

throw ContainerizationError(
.internalError,
message: "failed to find runtime plugin \(config.runtimeHandler)"
)
}
try Self.registerService(
plugin: plugin,
loader: loader,
configuration: config,
path: dir
)
} catch {
try? FileManager.default.removeItem(at: dir)
log.warning("failed to load container bundle at \(dir.path)")
Expand DownExpand Up@@ -159,10 +152,7 @@ public actor ContainersService {
)
}

let runtimePlugin = self.runtimePlugins.filter {
$0.name == configuration.runtimeHandler
}.first
guard let runtimePlugin else {
guard self.runtimePlugins.first(where: { $0.name == configuration.runtimeHandler }) != nil else {
throw ContainerizationError(
.notFound,
message: "unable to locate runtime plugin \(configuration.runtimeHandler)"
Expand All@@ -185,13 +175,6 @@ public actor ContainersService {
try bundle.setContainerRootFs(cloning: imageFs)
try bundle.write(filename: "options.json", value: options)

try Self.registerService(
plugin: runtimePlugin,
loader: self.pluginLoader,
configuration: configuration,
path: path
)

let snapshot = ContainerSnapshot(
configuration: configuration,
status: .stopped,
Expand DownExpand Up@@ -223,6 +206,16 @@ public actor ContainersService {
return
}

let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
try Self.registerService(
plugin: self.runtimePlugins.first { $0.name == config.runtimeHandler }!,
loader: self.pluginLoader,
configuration: config,
path: path
)

let runtime = state.snapshot.configuration.runtimeHandler
let sandboxClient = try await SandboxClient.create(
id: id,
Expand DownExpand Up@@ -457,15 +450,23 @@ public actor ContainersService {

await self.exitMonitor.stopTracking(id: id)

// Try and shutdown the runtime helper.
do {
self.log.info("Shutting down sandbox service for \(id)")
// Shutdown and deregister the sandbox service
self.log.info("Shutting down sandbox service for \(id)")

let client = try state.getClient()
try await client.shutdown()
} catch {
self.log.error("failed to shutdown sandbox service for \(id): \(error)")
}
let path = self.containerRoot.appendingPathComponent(id)
let bundle = ContainerClient.Bundle(path: path)
let config = try bundle.configuration
let label = Self.fullLaunchdServiceLabel(
runtimeName: config.runtimeHandler,
instanceId: id
)

let client = try state.getClient()
try await client.shutdown()
Comment on lines +464 to +465

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I still think shutdown shouldn't be fatal and we can leave what we had as it's mostly best effort cleanup on the sb services end, I just meant to not ignore all of the errors like what you had in your original change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're in a weird spot if deregistration fails though. Curious on your thoughts on how to handle that.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

ahh, If deregister fails, we could catch it and attempt kill SIGKILL + deregister as a fallback?


// Deregister the service, launchd will terminate the process
try ServiceManager.deregister(fullServiceLabel: label)
self.log.info("Deregistered sandbox service for \(id)")

state.snapshot.status = .stopped
state.snapshot.networks = []
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -272,15 +272,6 @@ public actor SandboxService {
case .created, .stopped(_), .stopping:
await self.setState(.shuttingDown)

Task {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it that containers won't ever stop gracefully anymore?

To ensure containers and attached volumes preserve written data don't we want something like:

  • Send SIGTERM to the primary workload and additional processes (execs)
  • Wait a certain amount of time for the processes to complete and be reaped and then vminitd terminates normally and the VM shuts down of its own accord
  • If this doesn't happen within a certain time shut down the VM forcefully

This isn't unlike what launchd does for macOS services

@dcantahdcantahNov 19, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Truthfully we should ensure the container (singular as that's all we support currently, but can be expanded to whatever the N is) is dead in shutdown. If the sandbox svc is still servicing any containers we should return an error. Shutdown should solely be a final little handshake to cleanup some possible resources before getting killed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the sandbox svc is still servicing any containers we should return an error.

We should return an error for what? That the container cannot be stopped?

What should the UX be for stop, given that properly stopping a container (or pod) can be a somewhat slow operation?

How best do we handle cases where a container (or pod) workload processes don't shut down in a timely manner?

If container stop c1 c2 c3 c4 signals these four containers to shut down, do we want to return immediately after telling them, or wait until we know that all are in the stopped state? The former is more responsive but can produce the condition that prompted this issue.

@dcantahdcantahNov 20, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should return an error for what? That the container cannot be stopped?

No, if there are still containers running in the handler for shutdown on any given sandbox svc we should throw an error. I/we should probably spend a week documenting the behaviors of the various rpcs so folks know what we expect the behavior is for every call, but I was modeling shutdown much after containerd's. It's meant as a final place to do any resource cleanup (possibly none like in our case, but depends on the implementation) after we've gone through the rounds already and stopped (or they may have exited on their own) any containers.

do {
try await Task.sleep(for: .seconds(5))
} catch {
self.log.error("failed to sleep before shutting down SandboxService: \(error)")
}
self.log.info("Shutting down SandboxService")
exit(0)
}
default:
throw ContainerizationError(
.invalidState,
Expand Down