DNA //evolutions

TourOptimizer REST Server

Deploy and operate JOpt.TourOptimizer as a reactive Spring WebFlux service with an OpenAPI 3 contract.


Overview



Why WebFlux and reactive

Optimization services run in bursty, concurrent scenarios: batch planning, interactive UI runs, multiple teams submitting jobs simultaneously, CI regression pipelines. TourOptimizer uses Spring WebFlux and reactive patterns to keep the HTTP layer non-blocking, support high concurrency for status and progress polling without thread starvation, and integrate naturally with the reactive event streams emitted by the Java core engine (progress percentages, warnings, errors, status transitions). The optimizer itself is compute-heavy and runs on its own thread pool. WebFlux keeps the service layer scalable and responsive regardless of how many connections are open.


Swagger and OpenAPI

The OpenAPI schema is derived from the snapshot model inside the Java library via annotations. The REST contract always matches the SDK snapshot definition, generated clients stay aligned with the server, and snapshots remain reproducible across environments.

  • Swagger UI: http://localhost:8081/swagger-ui/index.html
  • OpenAPI JSON: http://localhost:8081/v3/api-docs

Swagger Endpoint UISwagger Endpoint UI


Run locally with Docker

Minimal start (sync mode only, no database):

docker run -d --rm --name jopt-touroptimizer \
  -p 8081:8081 \
  -e SPRING_PROFILES_ACTIVE=cors \
  dnaevolutions/jopt_touroptimizer:latest

Full start (all features enabled — sync + database + all endpoints):

# Step 1 — Create a network
docker network create mongonetwork

# Step 2 — Start MongoDB
docker run -d --name dnamongo --network mongonetwork \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=dnauser \
  -e MONGO_INITDB_ROOT_PASSWORD=dnapwd \
  mongo:latest

# Step 3 — Start TourOptimizer
docker run --rm --name jopt-touroptimizer \
  --network mongonetwork \
  -p 8081:8081 \
  -e SPRING_PROFILES_ACTIVE=cors \
  -e DNA_DATABASE_ACTIVE=true \
  -e DNA_DATABASE_URI="mongodb://dnauser:dnapwd@dnamongo:27017/admin" \
  -e DNA_DATABASE_DB=touroptimizer \
  -e DNA_SHOW_SYNCH_CONTROLLERS=true \
  -e DNA_DATABASE_FREE_SEARCH_ENABLED=true \
  -e DNA_DATABASE_JOB_IMPORT_ENABLED=true \
  -e DNA_WEBHOOK_VALIDATION=relaxed \
  dnaevolutions/jopt_touroptimizer:latest

If your REST client runs inside another container on the same machine, use http://host.docker.internal:8081 instead of http://localhost:8081.

For platform-specific deployment help see:


Endpoint groups and feature flags

Endpoints are activated conditionally based on application properties and environment variables. Endpoints that are not active in a given deployment are absent from the service and do not appear in the runtime OpenAPI spec.

Job endpoints (/api/v1/jobs/*)

The primary integration model for all deployments with a connected database. Submit a job and receive a jobId. Use that token to poll and retrieve results at any time without holding an HTTP connection open. Requires DNA_DATABASE_ACTIVE=true.

MethodPathDescriptionCondition
POST/api/v1/jobsSubmit an async optimization jobDatabase
GET/api/v1/jobs/{jobId}/resultRetrieve the full optimization resultDatabase
GET/api/v1/jobs/{jobId}/solutionRetrieve the solution payload onlyDatabase
GET/api/v1/jobs/{jobId}/statusPoll job statusDatabase
GET/api/v1/jobs/{jobId}/progressRetrieve progress snapshotsDatabase
GET/api/v1/jobs/{jobId}/warningsRetrieve warning messagesDatabase
GET/api/v1/jobs/{jobId}/errorsRetrieve error messagesDatabase
GET/api/v1/jobs/{jobId}/exportDownload result as a ZIP archiveDatabase
POST/api/v1/jobs/{jobId}/stopSend graceful stop signal to a running jobDatabase
DELETE/api/v1/jobs/{jobId}Delete all persisted data for a jobDatabase
POST/api/v1/jobs/searchSearch jobs by metadata criteriaDatabase + free-search enabled
POST/api/v1/jobs/importImport a pre-computed result without running the optimizerDatabase + import enabled

All job endpoints require the X-Tenant-Id header. In SaaS deployments this is injected by the API gateway. In local and on-premise deployments any fixed string is acceptable (for example local or my-tenant).

Synchronous run endpoints (/api/v1/runs/*)

For short optimizations (up to a few minutes) where holding the connection open is acceptable. Each run is isolated by a runId — multiple concurrent runs are fully supported. Requires DNA_SHOW_SYNCH_CONTROLLERS=true.

MethodPathDescription
POST/api/v1/runsStart a run, return runId immediately (HTTP 202)
GET/api/v1/runs/{runId}/resultBlock until done, return the full result
GET/api/v1/runs/{runId}/solutionBlock until done, return the solution only
DELETE/api/v1/runs/{runId}Stop the run gracefully
GET/api/v1/runs/{runId}/startedOne-shot signal when the run transitions to active

For optimizations that take longer than a few minutes, use the job endpoints instead.

SSE stream endpoints (/api/v1/runs/{runId}/stream/*)

Server-Sent Event streams scoped to a specific sync run. Subscribe while the run is in progress to receive live events. Each run has independent, isolated stream subscriptions. Requires DNA_SHOW_SYNCH_CONTROLLERS=true.

MethodPathEvent type
GET/api/v1/runs/{runId}/stream/progressProgress percentage and timing
GET/api/v1/runs/{runId}/stream/statusLifecycle status transitions
GET/api/v1/runs/{runId}/stream/warningsNon-fatal solver warnings
GET/api/v1/runs/{runId}/stream/errorsSolver error events

Health endpoint

MethodPathDescription
GET/api/v1/healthService liveness and readiness

Configuration reference

JOpt / DNA properties

PropertyDefaultEnvironment variableDescription
touroptimizer.debug.activefalseDNA_IS_DEBUGEnable debug mode
touroptimizer.elementslimit.activefalseDNA_HAS_ELEMENT_LIMITSCap the number of nodes and resources per request
touroptimizer.elementslimit.count100DNA_ELEMENT_LIMITS_COUNTLimit cap. Only active when elementslimit.active=true
touroptimizer.security.database-enabledtrueDNA_DATABASE_ACTIVEEnable MongoDB and all job endpoints
touroptimizer.security.database-download-enabledtrueDNA_DATABASE_DOWNLOAD_ACTIVEEnable result download endpoints
touroptimizer.security.database-clean-rate-seconds7200DNA_DATABASE_CLEAN_SECONDSHow often (in seconds) to scan for expired documents
touroptimizer.security.database-free-search-enabledtrueDNA_DATABASE_FREE_SEARCH_ENABLEDEnable POST /api/v1/jobs/search
touroptimizer.security.database-job-import-enabledtrueDNA_DATABASE_JOB_IMPORT_ENABLEDEnable POST /api/v1/jobs/import
touroptimizer.security.kms-providernoneDNA_KMS_PROVIDERKMS provider: none, local (dev), or azure (production)
touroptimizer.security.webhook-validationstrictDNA_WEBHOOK_VALIDATIONWebhook URL validation policy: strict (HTTPS + public addresses only), relaxed (HTTP + private addresses allowed), none (no validation, local dev only)
touroptimizer.security.default-lic(empty)DNA_DEFAULT_LICDefault fallback JSON license string
touroptimizer.security.plugins-enabledtrueDNA_PLUGINS_ACTIVEEnable optimization plugins
touroptimizer.security.protection-enabledfalseDNA_SECURITY_ENABLEDEnable password protection on Swagger UI
touroptimizer.security.userdnaDNA_USERUsername for Swagger UI password protection
touroptimizer.security.passwordjoptDNA_USERPassword for Swagger UI password protection
touroptimizer.security.whitelistips(empty)DNA_IP_WHITELISTComma-separated list of allowed IP addresses
touroptimizer.security.server-url/DNA_SERVER_URLBase server URL shown in the OpenAPI spec
touroptimizer.controller.show-synchtrueDNA_SHOW_SYNCH_CONTROLLERSEnable synchronous run and stream endpoints
touroptimizer.controller.show-deprecatedfalseDNA_SHOW_DEPRECATED_CONTROLLERSEnable legacy controller paths (to be removed)

Spring / WebFlux / springdoc properties

PropertyDefaultDescription
server.port8081HTTP listen port
server.http2.enabledtrueEnable HTTP/2
server.compression.enabledtrueEnable response compression
server.compression.min-response-size1024Minimum response size to compress (bytes)
server.forward-headers-strategyframeworkReverse proxy header handling
server.error.include-messagealwaysInclude error message in HTTP error responses
spring.data.mongodb.urimongodb://dnauser:dnapwd@localhost:27017/adminMongoDB connection URI (env: DNA_DATABASE_URI)
spring.data.mongodb.databasetouroptimizerMongoDB database name (env: DNA_DATABASE_DB)
spring.http.codecs.max-in-memory-size250MBMaximum in-memory buffer for reactive codec
spring.banner.locationclasspath:/banner/touroptimizerbanner.txtSpring Boot startup banner
spring.output.ansi.enabledDETECTANSI colour in banner and logs: DETECT, ALWAYS, or NEVER
springdoc.api-docs.enabledtrueServe the OpenAPI JSON document
springdoc.api-docs.path/v3/api-docsOpenAPI JSON path (env: DNA_API_DOCS_PATH)
springdoc.api-docs.versionOPENAPI_3_0OpenAPI spec version
springdoc.swagger-ui.disable-swagger-default-urltrueSuppress the default Swagger petstore URL
springdoc.writer-with-default-pretty-printertruePretty-print the OpenAPI JSON
springdoc.show-actuatorfalseInclude actuator endpoints in Swagger UI
debugfalseSpring Boot debug logging (env: DNA_SERVER_DEBUG)

Container environment variable summary

VariableDefaultPurpose
SPRING_PROFILES_ACTIVE(none)Spring profile selection. Use cors to enable browser-friendly CORS.
DNA_DATABASE_ACTIVEtrueEnable MongoDB and all job endpoints
DNA_DATABASE_URImongodb://dnauser:dnapwd@localhost:27017/adminMongoDB connection string
DNA_DATABASE_DBtouroptimizerMongoDB database name
DNA_SHOW_SYNCH_CONTROLLERStrueEnable sync run endpoints
DNA_DATABASE_FREE_SEARCH_ENABLEDtrueEnable the job search endpoint
DNA_DATABASE_JOB_IMPORT_ENABLEDtrueEnable the job import endpoint
DNA_KMS_PROVIDERnoneKMS provider: none, local, or azure
DNA_WEBHOOK_VALIDATIONstrictWebhook URL validation: strict, relaxed, or none
DNA_SHOW_DEPRECATED_CONTROLLERSfalseShow legacy controller paths
JAVA_TOOL_OPTIONS(none)JVM flags (memory, GC tuning, diagnostics)

References


A product by DNA Evolutions GmbH ©