Skip to main content

Migration Guide: v0.3.0

This guide covers upgrading from v0.2.x to v0.3.0. All new features are opt-in — existing code continues to work without changes.

Smooth Upgrade Path

v0.3.0 is fully backward-compatible. You can upgrade dependencies, verify tests pass, and adopt new features incrementally. No code changes are required for the upgrade itself.

Summary

v0.3.0 introduces:

  • SPI (Service Provider Interface) — plug in metrics, tracing, event listeners, caching
  • Execution lifecycle — cancellation, circuit breakers, graceful shutdown, backpressure
  • HTTP hardening — authentication, CORS, rate limiting, deep health checks
  • Deployment artifacts — Dockerfile, Docker Compose, Kubernetes manifests, fat JAR
  • Bounded scheduler — priority-based scheduling with configurable concurrency
  • Documentation — embedding guide, security model, performance tuning, error reference

Non-Breaking Changes

Zero-Overhead by Default

All new features are disabled by default, meaning your application has the exact same behavior and performance characteristics as v0.2.x until you explicitly opt in.

All new features are disabled by default. Your existing code works identically:

FeatureDefault StateImpact When Disabled
ConstellationBackendsAll fields no-opZero overhead
Circuit breakersNot configuredNo rejection
AuthenticationNot configuredNo auth checks
CORSNot configuredNo CORS headers
Rate limitingNot configuredNo rate limits
Bounded schedulerUnbounded (default)Same as before
Lifecycle managementNot configuredNo graceful shutdown
Health endpoints/health unchangedSame response

API Additions

ConstellationBackends

New bundle type for pluggable integrations:

import io.constellation.spi.ConstellationBackends

// Before (v0.2.x): no backends concept
val constellation = ConstellationImpl.init

// After (v0.3.0): optionally configure backends
val constellation = ConstellationImpl.builder()
.withBackends(ConstellationBackends(
metrics = myMetrics, // MetricsProvider
tracer = myTracer, // TracerProvider
listener = myListener // ExecutionListener
))
.build()

ConstellationImpl.init still works and uses ConstellationBackends.defaults (all no-op).

ConstellationBuilder

New builder pattern for ConstellationImpl:

// Before: ConstellationImpl.init
val constellation = ConstellationImpl.init

// After: builder pattern (init still works)
val constellation = ConstellationImpl.builder()
.withScheduler(scheduler)
.withBackends(backends)
.withDefaultTimeout(60.seconds)
.withLifecycle(lifecycle)
.build()

CancellableExecution

API Changed in v1.0

The runDagCancellable method was removed in v1.0. Use IO.timeout for cancellation as shown below.

New trait for cancelling running pipelines:

// Note: runDagCancellable was subsequently removed in v1.0.
// Use IO.timeout for cancellation:
constellation.run(compiled.pipeline, inputs)
.timeout(30.seconds)

CircuitBreaker

New module-level circuit breaker:

import io.constellation.execution.{CircuitBreaker, CircuitBreakerConfig}

val cb = CircuitBreaker.create("my-module", CircuitBreakerConfig(
failureThreshold = 5,
resetDuration = 30.seconds,
halfOpenMaxProbes = 1
))

ConstellationLifecycle

New lifecycle manager for graceful shutdown:

import io.constellation.execution.ConstellationLifecycle

for {
lifecycle <- ConstellationLifecycle.create
constellation <- ConstellationImpl.builder()
.withLifecycle(lifecycle)
.build()
// ... application runs ...
_ <- lifecycle.shutdown(drainTimeout = 30.seconds)
} yield ()

GlobalScheduler Configuration

New bounded scheduler with priority ordering:

import io.constellation.execution.GlobalScheduler

// Before: only unbounded (implicit)
val constellation = ConstellationImpl.init

// After: optionally bounded
GlobalScheduler.bounded(
maxConcurrency = 16,
maxQueueSize = 1000,
starvationTimeout = 30.seconds
).use { scheduler =>
ConstellationImpl.builder()
.withScheduler(scheduler)
.build()
}

ServerBuilder Methods

New builder methods on ConstellationServer.builder():

ConstellationServer.builder(constellation, compiler)
.withAuth(AuthConfig(...)) // New
.withCors(CorsConfig(...)) // New
.withRateLimit(RateLimitConfig(...)) // New
.withHealthChecks(HealthCheckConfig(...)) // New
.run

New Health Endpoints

EndpointStatusResponse
GET /healthUnchanged{"status": "ok"}
GET /health/liveNew{"status": "alive"} (always 200)
GET /health/readyNew{"ready": true} or 503
GET /health/detailNewComponent diagnostics (opt-in)

How to Opt In

SPI Backends

Implement one or more SPI traits and pass them to ConstellationBackends:

val backends = ConstellationBackends(
metrics = new MyPrometheusMetrics(),
tracer = new MyOtelTracer(),
listener = new MyKafkaListener(),
cache = Some(new MyRedisCache())
)

val constellation = ConstellationImpl.builder()
.withBackends(backends)
.build()

See the SPI Integration Guides for implementation examples.

Lifecycle Management

for {
lifecycle <- ConstellationLifecycle.create
constellation <- ConstellationImpl.builder()
.withLifecycle(lifecycle)
.build()
// On shutdown signal:
_ <- lifecycle.shutdown(drainTimeout = 30.seconds)
} yield ()

HTTP Hardening

Each feature is independent — enable any combination:

ConstellationServer.builder(constellation, compiler)
// Auth: API key + role-based access
.withAuth(AuthConfig(apiKeys = Map("key1" -> ApiRole.Admin)))
// CORS: specific origins
.withCors(CorsConfig(allowedOrigins = Set("https://myapp.com")))
// Rate limiting: per-IP token bucket
.withRateLimit(RateLimitConfig(requestsPerMinute = 100))
// Health: enable detail endpoint
.withHealthChecks(HealthCheckConfig(enableDetailEndpoint = true))
.run

Circuit Breakers

import io.constellation.execution.CircuitBreakerConfig

val constellation = ConstellationImpl.builder()
.withCircuitBreaker(CircuitBreakerConfig(
failureThreshold = 5,
resetDuration = 30.seconds
))
.build()

New Environment Variables

All environment variables are prefixed with CONSTELLATION_:

VariableDefaultDescriptionPhase
CONSTELLATION_PORT8080HTTP server portExisting
CONSTELLATION_SCHEDULER_ENABLEDfalseEnable bounded schedulerPhase 5
CONSTELLATION_SCHEDULER_MAX_CONCURRENCY16Max concurrent tasksPhase 5
CONSTELLATION_SCHEDULER_STARVATION_TIMEOUT30sStarvation preventionPhase 5
CONSTELLATION_API_KEYS(none)API keys as key:Role,...Phase 3
CONSTELLATION_CORS_ORIGINS(none)CORS allowed originsPhase 3
CONSTELLATION_RATE_LIMIT_RPM100Requests per minutePhase 3
CONSTELLATION_RATE_LIMIT_BURST20Rate limit burst sizePhase 3
CONSTELLATION_CST_DIR(cwd)Dashboard script directoryExisting
CONSTELLATION_SAMPLE_RATE1.0Execution sampling rateExisting
CONSTELLATION_MAX_EXECUTIONS1000Max stored executionsExisting
CONSTELLATION_DEBUGfalseEnable debug modeExisting

Deployment Artifacts

v0.3.0 includes reference deployment artifacts:

ArtifactLocationPurpose
DockerfileDockerfileMulti-stage build (JDK 17 builder, JRE 17 runtime)
Docker Composedocker-compose.ymlDev stack with health checks
K8s manifestsdeploy/k8s/Namespace, Deployment, Service, ConfigMap
Fat JARmake assemblySingle executable JAR

Build and run:

make assembly       # Build fat JAR
make docker-build # Build Docker image
make docker-run # Run in Docker