Run python nodes out of process, with modules of their own

User code no longer execs in the engine. A pool of persistent worker
subprocesses speaks one JSON object per line; the controller installs a
proxy as the node's function, so every execution path funnels through it
and the pipeline is untouched. A crash costs one subprocess, a per-node
timeout is a kill, and cancelling from the canvas is that same kill.

The workers run a venv of the user's own on the data volume, filled from
a pip manifest versioned beside the flows. Applying it retires the
workers and rebuilds, so a package lands without restarting the engine.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MeiWk3Yq12n2pTvnQWYvt
This commit is contained in:
2026-08-16 21:43:36 +02:00
co-authored by Claude Fable 5
parent 979c9d3c1f
commit f300c43f3a
27 changed files with 1536 additions and 46 deletions
+21
View File
@@ -20,6 +20,7 @@ import { Route as ViewNameRouteImport } from './routes/view.$name'
import { Route as OauthAuthorizeRouteImport } from './routes/oauth.authorize'
import { Route as LayoutSettingsRouteImport } from './routes/_layout/settings'
import { Route as LayoutSecretsRouteImport } from './routes/_layout/secrets'
import { Route as LayoutModulesRouteImport } from './routes/_layout/modules'
import { Route as LayoutAlertsRouteImport } from './routes/_layout/alerts'
import { Route as LayoutAdminRouteImport } from './routes/_layout/admin'
import { Route as LayoutFlowsIndexRouteImport } from './routes/_layout/flows/index'
@@ -80,6 +81,11 @@ const LayoutSecretsRoute = LayoutSecretsRouteImport.update({
path: '/secrets',
getParentRoute: () => LayoutRoute,
} as any)
const LayoutModulesRoute = LayoutModulesRouteImport.update({
id: '/modules',
path: '/modules',
getParentRoute: () => LayoutRoute,
} as any)
const LayoutAlertsRoute = LayoutAlertsRouteImport.update({
id: '/alerts',
path: '/alerts',
@@ -119,6 +125,7 @@ export interface FileRoutesByFullPath {
'/signup': typeof SignupRoute
'/admin': typeof LayoutAdminRoute
'/alerts': typeof LayoutAlertsRoute
'/modules': typeof LayoutModulesRoute
'/secrets': typeof LayoutSecretsRoute
'/settings': typeof LayoutSettingsRoute
'/oauth/authorize': typeof OauthAuthorizeRoute
@@ -136,6 +143,7 @@ export interface FileRoutesByTo {
'/signup': typeof SignupRoute
'/admin': typeof LayoutAdminRoute
'/alerts': typeof LayoutAlertsRoute
'/modules': typeof LayoutModulesRoute
'/secrets': typeof LayoutSecretsRoute
'/settings': typeof LayoutSettingsRoute
'/oauth/authorize': typeof OauthAuthorizeRoute
@@ -155,6 +163,7 @@ export interface FileRoutesById {
'/signup': typeof SignupRoute
'/_layout/admin': typeof LayoutAdminRoute
'/_layout/alerts': typeof LayoutAlertsRoute
'/_layout/modules': typeof LayoutModulesRoute
'/_layout/secrets': typeof LayoutSecretsRoute
'/_layout/settings': typeof LayoutSettingsRoute
'/oauth/authorize': typeof OauthAuthorizeRoute
@@ -175,6 +184,7 @@ export interface FileRouteTypes {
| '/signup'
| '/admin'
| '/alerts'
| '/modules'
| '/secrets'
| '/settings'
| '/oauth/authorize'
@@ -192,6 +202,7 @@ export interface FileRouteTypes {
| '/signup'
| '/admin'
| '/alerts'
| '/modules'
| '/secrets'
| '/settings'
| '/oauth/authorize'
@@ -210,6 +221,7 @@ export interface FileRouteTypes {
| '/signup'
| '/_layout/admin'
| '/_layout/alerts'
| '/_layout/modules'
| '/_layout/secrets'
| '/_layout/settings'
| '/oauth/authorize'
@@ -311,6 +323,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof LayoutSecretsRouteImport
parentRoute: typeof LayoutRoute
}
'/_layout/modules': {
id: '/_layout/modules'
path: '/modules'
fullPath: '/modules'
preLoaderRoute: typeof LayoutModulesRouteImport
parentRoute: typeof LayoutRoute
}
'/_layout/alerts': {
id: '/_layout/alerts'
path: '/alerts'
@@ -372,6 +391,7 @@ const CanvasRouteWithChildren =
interface LayoutRouteChildren {
LayoutAdminRoute: typeof LayoutAdminRoute
LayoutAlertsRoute: typeof LayoutAlertsRoute
LayoutModulesRoute: typeof LayoutModulesRoute
LayoutSecretsRoute: typeof LayoutSecretsRoute
LayoutSettingsRoute: typeof LayoutSettingsRoute
LayoutIndexRoute: typeof LayoutIndexRoute
@@ -382,6 +402,7 @@ interface LayoutRouteChildren {
const LayoutRouteChildren: LayoutRouteChildren = {
LayoutAdminRoute: LayoutAdminRoute,
LayoutAlertsRoute: LayoutAlertsRoute,
LayoutModulesRoute: LayoutModulesRoute,
LayoutSecretsRoute: LayoutSecretsRoute,
LayoutSettingsRoute: LayoutSettingsRoute,
LayoutIndexRoute: LayoutIndexRoute,