Skip to content

JS Execution Engine

The JS Execution Service is responsible for running user-defined scripts in MapexOS. It executes the decode → validate → transform pipeline defined in Asset Templates, converting raw payloads into standardized events.

Applies to v1.0.0 — V8 isolates, worker threads, bytecode caching, 4-level cache pipeline, execution limits, and tenant isolation.


Why JavaScript?

MapexOS chose JavaScript for template scripts because:

  • Universal familiarity: most integration teams know JavaScript
  • Rich ecosystem: JSON manipulation, date handling, string processing
  • V8 performance: Google's V8 engine is highly optimized
  • Isolation: V8 isolates provide memory and execution isolation

Execution pipeline

Each event ingested by MapexOS goes through the template pipeline:

txt
Raw Payload → Decode → Validate → Transform → Standard Event

Pipeline stages

StagePurposeScript function
DecodeParse raw bytes/JSON into a structured objectdecode(payload, metadata)
ValidateCheck required fields, types, rangesvalidate(decoded, metadata)
TransformMap to Standard Event schema + EVA fieldstransform(validated, metadata)

Each stage is a JavaScript function defined in the Asset Template. If any stage fails, the event is rejected with a structured error.


V8 Isolates

MapexOS uses V8 isolates to execute scripts securely:

  • Memory isolation: each isolate has its own heap (no cross-tenant memory access)
  • Execution isolation: scripts cannot access the host process or other isolates
  • Resource limits: CPU time and memory ceilings are enforced per execution

How isolates work

txt
┌─────────────────────────────────────────┐
│           JS Execution Service          │
├─────────────────────────────────────────┤
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  │
│  │ Isolate │  │ Isolate │  │ Isolate │  │
│  │ Tenant A│  │ Tenant B│  │ Tenant C│  │
│  └─────────┘  └─────────┘  └─────────┘  │
│                                         │
│  Pooled isolates with bytecode cache    │
└─────────────────────────────────────────┘

Worker threads

To maximize throughput, the JS Execution Service uses worker threads:

  • Parallel execution: multiple scripts run concurrently
  • Non-blocking: main thread handles orchestration, workers execute scripts
  • Pool management: workers are reused to avoid startup overhead

Scaling

txt
JS Execution Service × N replicas
  └── Worker Pool per replica
        └── Isolate per execution context

Scale the service horizontally to increase scripts/second capacity.


4-Level cache pipeline

For optimal performance, MapexOS caches compiled scripts at multiple levels:

txt
L0 (RAM) → L1 (NVMe/SSD) → L2 (MinIO/S3) → Compile fallback

Cache levels

LevelStorageLatencyDescription
L0In-memory (RAM)~μsHot scripts and bytecode
L1Local disk (NVMe/SSD)~msWarm scripts, persists across restarts
L2Object storage (MinIO/S3)~10-100msShared cache across replicas
FallbackOn-demand compile~10-50msFirst execution of new/updated script

Cache keys

Cache keys are scoped to prevent cross-tenant contamination:

txt
{orgId}:{templateId}:{templateVersion}:{stage}

Example:

txt
org-123:tmpl-456:v3:decode
org-123:tmpl-456:v3:validate
org-123:tmpl-456:v3:transform

Bytecode caching

V8 can serialize compiled bytecode, avoiding recompilation:

  1. First execution: script is parsed and compiled
  2. Bytecode cached: compiled bytecode is stored at L0/L1/L2
  3. Subsequent executions: bytecode is loaded directly (skip parse/compile)

This significantly reduces latency for frequently-used templates.


Execution limits

MapexOS enforces strict limits to protect the platform:

Per-execution limits

LimitDefaultPurpose
CPU timeout100msMaximum execution time per script
Memory ceiling64MBMaximum heap size per isolate
Stack depth1000Maximum call stack depth

Per-tenant quotas (configurable)

QuotaDescription
Executions/secondRate limit per tenant
Concurrent executionsMax parallel scripts per tenant
Script sizeMaximum bytes per script

Limits are configurable per deployment. Adjust based on your workload and infrastructure capacity.


Script context (available APIs)

Scripts have access to a limited, sandboxed API:

Available

APIDescription
JSON.parse() / JSON.stringify()JSON manipulation
DateDate/time operations
MathMathematical functions
String / Array / ObjectStandard data types
console.log()Logging (captured for debugging)
BufferBinary data handling
TextEncoder / TextDecoderText encoding

Not available (by design)

APIReason
fetch() / XMLHttpRequestNo network access from scripts
require() / importNo module loading
fs / processNo file system or process access
eval() / Function()Disabled for security
setTimeout / setIntervalNo async timers

Scripts are synchronous and deterministic. Side effects (HTTP calls, notifications) are handled by Triggers, not scripts.


Error handling

When a script fails, MapexOS captures:

  • Error type: syntax, runtime, timeout, memory
  • Error message: description of the failure
  • Stage: which pipeline stage failed (decode/validate/transform)
  • Stack trace: for debugging (when debug mode is enabled)

Error categories

CategoryDescriptionAction
Syntax errorInvalid JavaScriptFix script in template
Runtime errorException during executionCheck logic and input
TimeoutExceeded CPU limitOptimize script or increase limit
Memory limitExceeded heap sizeReduce memory usage
Validation rejectionScript returned invalid resultCheck validation logic

Debugging

Debug mode per asset

Enable debug mode on specific assets for detailed logging:

txt
debugEnabled = true  → Full execution logs (input, output, duration)
debugEnabled = false → Error logs only (default)

Execution logs

When debug is enabled, logs include:

  • Input payload
  • Decoded output
  • Validation result
  • Transformed event
  • Execution duration per stage
  • Any warnings or errors

Production note: Keep debug disabled in production to reduce log volume and cost. Enable only during investigation.


Performance guidelines

Write efficient scripts

javascript
// GOOD: Direct property access
function decode(payload) {
  return {
    temperature: payload.t,
    humidity: payload.h
  };
}

// AVOID: Unnecessary operations
function decode(payload) {
  const copy = JSON.parse(JSON.stringify(payload)); // Unnecessary copy
  return { temperature: copy.t, humidity: copy.h };
}

Avoid common pitfalls

PitfallImpactSolution
Large loopsTimeoutLimit iterations, use built-in methods
Deep recursionStack overflowUse iterative approach
Large string concatenationMemory pressureUse arrays and join
Excessive loggingPerformance + costLog only errors in production

Security model

Tenant isolation

  • Scripts from different tenants never share memory
  • Cache keys include tenant ID
  • Execution metrics are scoped to tenant

No network access

Scripts cannot make HTTP calls or access external systems. All external actions are handled by:

  1. Triggers: for HTTP webhooks, notifications, etc.
  2. Route Groups: for event fan-out to external systems

Secrets handling

Scripts can reference secrets stored securely:

javascript
function transform(validated, metadata) {
  // Secrets are injected by the platform, not hardcoded
  const apiKey = metadata.secrets.API_KEY;
  // ...
}

Secrets are never logged. The platform injects them at runtime.


Monitoring

Key metrics

MetricDescription
js_executions_totalTotal script executions
js_execution_duration_msExecution time histogram
js_execution_errors_totalErrors by type
js_cache_hits_totalCache hits by level
js_cache_misses_totalCache misses
js_isolate_pool_sizeCurrent isolate pool size

Alerting recommendations

  • High error rate: > 1% of executions failing
  • High latency: p99 > 50ms
  • Cache miss rate: > 10% (indicates cold cache or churn)

Next steps

Business Source License (BSL 1.1)