Joblet is a micro-container runtime for running Linux jobs with: Process and filesystem isolation (PID namespace, chroot) Fine-grained CPU, memory, and IO throttling (cgroups v2) Secure job execution with mTLS and RBAC Built-in scheduler, SSE log streaming, and multi-core pinning Ideal for: Agentic AI Workloads (Untrusted code)
Joblet is a high-performance job execution system with a monorepo structure containing two main services and a CLI tool.
joblet/
├── cmd/
│ ├── joblet/ # Main service daemon
│ └── rnx/ # CLI client
├── internal/
│ ├── joblet/ # Main service implementation
│ ├── rnx/ # CLI implementation
│ └── proto/ # Internal protocol buffers (IPC, persist)
├── persist/ # Persistence service (sub-module)
│ ├── cmd/persist/
│ ├── internal/
│ └── go.mod # Separate Go module
├── state/ # State persistence service (sub-module)
│ ├── cmd/state/ # State service binary
│ ├── internal/
│ │ ├── storage/ # Backend interface (Memory, DynamoDB)
│ │ └── ipc/ # IPC server
│ └── go.mod # Separate Go module (AWS SDK dependencies)
├── api/
│ └── gen/ # Generated public API (from external joblet-proto)
├── pkg/ # Shared packages
│ ├── config/ # Configuration management
│ ├── logger/ # Logging utilities
│ ├── security/ # TLS/mTLS support
│ └── client/ # gRPC clients
└── scripts/ # Build and deployment scripts
bin/joblet:50051 (gRPC) or :443 on AWS/EC2bin/persistbin/state/opt/joblet/run/state-ipc.sock)bin/rnxflowchart TD
N1["RNX Client"] <-->|"gRPC :50051"| N2["Joblet Service (main)"]
N2 -->|"Unix Socket IPC (logs/metrics)"| N3["Persist (logs/metrics)"]
N2 -->|"Unix Socket IPC (job state)"| N4["State (job state)"]
N3 -->|gRPC| N5["RNX Queries (historical data)"]
N4 --> N6["Storage Backend (Memory/DynamoDB)"]
Joblet automatically spawns and supervises two subprocesses:
Both subprocesses are managed with:
Pdeathsig: SIGTERM ensures children terminate when parent diesjoblet.proto (external, versioned)github.com/ehsaniara/joblet-protoapi/gen/internal/proto/ipc.proto/opt/joblet/run/persist.sockinternal/proto/persist.protogithub.com/ehsaniara/joblet-protojoblet.protoapi/gen/joblet.pb.go, joblet_grpc.pb.gointernal/proto/ipc.proto - IPC messages (logs, metrics)persist.proto - Persistence service APIinternal/proto/gen/Both services use: /opt/joblet/config/joblet-config.yml
# Main service config (top-level)
server:
port: 50051
joblet:
maxConcurrentJobs: 100
# ... other main config
# Persist service config (nested)
persist:
server:
grpc_socket: "/opt/joblet/run/persist-grpc.sock" # Unix socket for gRPC queries
ipc:
socket: "/opt/joblet/run/persist-ipc.sock" # Unix socket for log/metric writes
# ... other persist config
The persist service automatically detects and reads from the persist: section.
Both services support TLS encryption:
scripts/certs_gen_embedded.shsecurity: sectionpersist.tls sectionpkg/security/tls.goLoadServerTLSConfig() - Server-side TLSLoadClientTLSConfig() - Client-side TLSmake all - Build all binariesmake joblet - Build main service onlymake rnx - Build CLI onlymake persist - Build persist service onlymake proto - Generate all proto filesmake clean - Remove build artifactsmake deploy - Deploy to remote servermake test - Run all testsProto generation uses two approaches:
scripts/generate-proto.sh - External public API
joblet-proto moduleapi/gen/go generate ./internal/proto - Internal protos (IPC and Persist)
internal/proto/ filesinternal/proto/gen/ipc/ and internal/proto/gen/persist///go:generate directives in internal/proto/generate.goDevelopers can regenerate protos with:
make proto # Regenerate all protos
go generate ./internal/proto # Regenerate internal protos only
flowchart TD
N1["RNX sends RunJob request → Joblet"] --> N2["Joblet creates job record in memory + sends to State (async IPC)"]
N2 --> N3["State persists job metadata to backend (Memory/DynamoDB)"]
N3 --> N4["Joblet creates isolated environment (cgroups, namespaces)"]
N4 --> N5["Joblet executes job and streams live logs → RNX"]
N5 --> N6["Joblet collects metrics (CPU, memory, GPU, I/O)"]
N6 --> N7["Joblet sends logs/metrics → Persist (via IPC)"]
N7 --> N8["Persist stores to disk (/opt/joblet/logs, /opt/joblet/metrics)"]
N8 --> N9["Joblet updates job status + sends to State (async IPC)"]
flowchart TD
N1["RNX sends QueryLogs request → Persist"] --> N2["Persist reads from disk storage"]
N2 --> N3["Persist streams results → RNX"]
flowchart TD
N1["Joblet job lifecycle events (create, update, complete) → State (async IPC)"] --> N2["State writes to backend (Memory/DynamoDB) with 5s timeout"]
N2 --> N3["On joblet restart: Joblet requests job sync → State"]
N3 --> N4["State reads from backend → returns all jobs"]
N4 --> N5["Joblet populates in-memory cache with persisted jobs"]
/opt/joblet/
├── bin/ # Binaries
│ ├── joblet
│ ├── rnx
│ ├── persist
│ └── state # State persistence service
├── config/ # Configuration
│ └── joblet-config.yml # Unified config (all services)
├── run/ # Runtime files
│ ├── persist-ipc.sock # IPC socket (log/metric writes)
│ ├── persist-grpc.sock # gRPC socket (historical queries)
│ └── state-ipc.sock # IPC socket (job state persistence)
├── jobs/ # Job workspaces
│ └── {job-uuid}/ # Per-job directory
├── logs/ # Historical logs
│ └── {job-uuid}/ # Per-job log files
├── metrics/ # Historical metrics
│ └── {job-uuid}/ # Per-job metric files
├── volumes/ # Named volumes
├── network/ # Network state
└── runtimes/ # Runtime environments
Single systemd service:
/opt/joblet/bin/joblet/opt/joblet/config/joblet-config.ymlmake deploy REMOTE_HOST=192.168.1.161 REMOTE_USER=jay
This builds all binaries, copies to remote server, and restarts services.
# Edit code in internal/, cmd/, or persist/
vim internal/joblet/core/executor.go
# For public API changes - update external joblet-proto repo
# For internal changes - edit internal/proto/*.proto
make proto
make clean
make all
make test
make deploy
github.com/ehsaniara/joblet./go.modgithub.com/ehsaniara/joblet-proto@v1.0.9 (external)github.com/ehsaniara/joblet/persist (local replace)github.com/ehsaniara/joblet/state (local replace)github.com/ehsaniara/joblet/persist./persist/go.modgithub.com/ehsaniara/joblet (local replace to parent)github.com/ehsaniara/joblet/state./state/go.modgithub.com/ehsaniara/joblet (local replace to parent)github.com/aws/aws-sdk-go-v2 (DynamoDB backend)github.com/aws/aws-sdk-go-v2/service/dynamodb (DynamoDB client)pkg/