Tutorial - Job-Based Fire and Forget Mode
Get in Touch
If you need assistance or have questions, we are here to help. Please reach out to us through our company website at www.dna-evolutions.com/contact.
Overview
- Introduction — Classic FAF vs. Job Mode
- How Job Mode Works
- The JobAcceptedResponse
- Tenant Isolation and Security
- Endpoint Reference
- The DatabaseJobItemSearch and DatabaseJobInfoSearch Models
- Step-by-Step: Running a Job-Mode Optimization
- Encryption at Rest
- KMS Envelope Encryption
- Encryption Mode Summary
- What Gets Stored in MongoDB
- Error Handling
Introduction
The classic Fire and Forget (FAF) mode lets you submit a long-running optimization without keeping the HTTP connection open. The server returns a boolean "started" signal, and you later search for results by creator name using the persistence-read endpoints.
Job Mode builds on this foundation and adds a structured, tenant-aware job lifecycle. Instead of a boolean, the server returns a JobAcceptedResponse containing a unique jobId. This single token is everything the client needs to track and retrieve the job — no searching by creator, no guessing which result belongs to which submission.
When to use which mode
Classic FAF (/api/optimizefaf/runFAF) | Job Mode (/api/job/optimizefaf/runFAF) | |
|---|---|---|
| Returns | true (optimization started) | JobAcceptedResponse with jobId |
| HTTP status | 200 OK | 202 Accepted |
| Result lookup | Search by creator via /api/db/read/ | Direct lookup by jobId + tenantId via /api/db/job/read/ |
| Multi-tenant | Manual — creator is user-provided | Built-in — tenantId from API gateway header |
| Concurrent jobs | Harder to distinguish (same creator, multiple runs) | Each job has its own unique jobId |
| Best for | Self-hosted single-tenant setups | Multi-tenant SaaS deployments, API-gateway-managed environments |
Job Mode does not replace classic FAF. Both modes coexist and share the same optimization engine, database, and persistence settings. Job Mode simply adds a structured job handle and enforces tenant scoping.
How Job Mode Works
The lifecycle of a job-mode optimization follows four phases:
1. Submit
The client sends a POST request to /api/job/optimizefaf/runFAF with the standard RestOptimization body and an X-Tenant-Id header (injected by the API gateway). The server generates a jobId, starts the optimization asynchronously, and immediately returns an HTTP 202 with the JobAcceptedResponse.
2. Poll
While the optimization is running, the client polls for progress, status, warnings, or errors using the job-based read endpoints under /api/db/job/read/. All requests require the jobId and tenantId via a DatabaseJobInfoSearch body — the server only returns data that belongs to the authenticated tenant.
3. Retrieve
Once the optimization completes (the status shows SUCCESS_WITH_SOLUTION or SUCCESS_WITHOUT_SOLUTION), the client retrieves the full result via /api/db/job/read/findOptimization using a DatabaseJobItemSearch body. If the data was encrypted with a client secret during submission, the same secret must be provided in this request body to decrypt the result. If KMS encryption was used by the server, decryption happens transparently — no secret is needed from the client.
4. Expire
Like classic FAF, persisted data has a configurable TTL (expiry in the persistenceSetting). After expiry, the data is automatically cleaned up by the scheduler.
The JobAcceptedResponse
When you submit a job, the server responds with HTTP 202 and the following body:
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"creatorHash": "11aa65b13c2a6d34f8727e82e403ce869e3bba1d35c45c595e8cc5ce5e74e57a",
"ident": "JOpt-Run-1774127074120",
"submittedAt": 1774131229940,
"status": "ACCEPTED"
}
| Field | Description |
|---|---|
jobId | A UUID v4 generated server-side before the async work begins. This is the primary handle for all polling and retrieval operations. |
creatorHash | The SHA-256 hash of the creator name from the request's creatorSetting. Matches the creator field in persisted metadata. |
ident | The user-defined label echoed back from the input. Useful for human identification of the run. |
submittedAt | Epoch-millisecond timestamp of when the job was accepted. |
status | Always ACCEPTED in the response. The actual optimization status is tracked in the database and can be polled via findStatus. |
Tenant Isolation and Security
Job Mode enforces tenant isolation at the API level. Every persisted document (result, progress, status, warning, error) is tagged with both a jobId and a tenantId. All read queries are automatically scoped by both fields — a client can only access data that matches its authenticated tenant.
How the tenantId flows
- The client authenticates with the API gateway (e.g. Azure API Management) via an API key or OAuth token.
- The gateway resolves the subscription to a tenant and injects the
X-Tenant-Idheader. - TourOptimizer reads the header server-side — the client cannot forge it.
- All persistence writes tag the data with this
tenantId. - All persistence reads filter by
tenantId— even if someone knows another tenant'sjobId, the query returns nothing.
The jobId is not a security token
The jobId is a convenience handle, not an access credential. Security is enforced by the tenantId (which comes from the verified gateway header), not by the secrecy of the jobId. The jobId is a UUID v4 with 122 bits of randomness, which makes it practically unguessable, but this is defense-in-depth — not the primary boundary.
Endpoint Reference
All job-mode endpoints are under the /api/job/ path prefix and require database mode to be enabled (DNA_DATABASE_ACTIVE=true).
Submit
| Method | Path | Request Body | Description |
|---|---|---|---|
POST | /api/job/optimizefaf/runFAF | RestOptimization | Submit an optimization job. Returns JobAcceptedResponse (HTTP 202). |
Required headers: X-Tenant-Id
Poll and Retrieve
| Method | Path | Request Body | Description |
|---|---|---|---|
POST | /api/db/job/read/findOptimization | DatabaseJobItemSearch | Retrieve the full optimization result (auto-detects encryption mode). |
POST | /api/db/job/read/findProgress | DatabaseJobInfoSearch | Retrieve progress snapshots. |
POST | /api/db/job/read/findStatus | DatabaseJobInfoSearch | Retrieve status updates (RUNNING, SUCCESS, ERROR). |
POST | /api/db/job/read/findWarning | DatabaseJobInfoSearch | Retrieve warning messages. |
POST | /api/db/job/read/findError | DatabaseJobInfoSearch | Retrieve error messages. |
The DatabaseJobItemSearch and DatabaseJobInfoSearch Models
Job-mode read endpoints use two request body models. Both require jobId and tenantId as mandatory fields.
DatabaseJobItemSearch
Used by findOptimization to retrieve the full optimization result. Includes an optional secret field for decrypting client-encrypted results. For KMS-encrypted or unencrypted results, the secret field can be omitted.
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "my-tenant-123",
"secret": "",
"timeOut": "PT1M"
}
| Field | Required | Description |
|---|---|---|
jobId | Yes | The unique job identifier from the JobAcceptedResponse. |
tenantId | Yes | The tenant identifier. Must match the X-Tenant-Id used during submission. |
secret | No | The client secret for decryption. Only required if the optimization was encrypted with a client-provided secret (CLIENT mode). Leave empty for KMS-encrypted or unencrypted data — the server handles decryption transparently. |
timeOut | Yes | Maximum time to wait for the database response. Default: PT1M (one minute). ISO 8601 duration format. |
DatabaseJobInfoSearch
Used by findProgress, findStatus, findWarning, and findError to retrieve stream data.
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "my-tenant-123",
"limit": 10,
"sortDirection": "DESC",
"timeOut": "PT1M"
}
| Field | Required | Description |
|---|---|---|
jobId | Yes | The unique job identifier from the JobAcceptedResponse. |
tenantId | Yes | The tenant identifier. Must match the X-Tenant-Id used during submission. |
limit | No | Maximum number of results to return. Results are sorted by creation time. Default behavior returns all matching entries. |
sortDirection | No | Sort direction for creation time: DESC (newest first, default) or ASC (oldest first). |
timeOut | No | Maximum time to wait for the database response. Default: PT1M. ISO 8601 duration format. |
Step-by-Step: Running a Job-Mode Optimization
This walkthrough assumes you have already set up MongoDB and TourOptimizer as described in the classic FAF tutorial (Steps 1–4).
Step 1: Submit the job
Send a POST to /api/job/optimizefaf/runFAF with your optimization input. Include the X-Tenant-Id header and the persistenceSetting in the extension.
Request:
POST /api/job/optimizefaf/runFAF
Content-Type: application/json
X-Tenant-Id: my-tenant-123
The request body is the standard RestOptimization JSON — identical to classic FAF. Make sure enablePersistence is set to true inside the persistenceSetting.
The secret field determines which encryption mode is used on the server:
secretis non-empty → CLIENT mode (you manage the key)secretis empty + KMS enabled on server → KMS mode (server manages the key, transparent to you)secretis empty + no KMS → no encryption
Response (HTTP 202):
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"creatorHash": "11aa65b13c2a6d34f8727e82e403ce869e3bba1d35c45c595e8cc5ce5e74e57a",
"ident": "JOpt-Run-1774127074120",
"submittedAt": 1774131229940,
"status": "ACCEPTED"
}
Save the jobId — you will need it for all subsequent requests.
Step 2: Poll for progress (optional)
While the optimization is running, you can check progress:
POST /api/db/job/read/findProgress
Content-Type: application/json
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "my-tenant-123"
}
The response is a stream of JOptOptimizationProgress objects showing the current stage and percentage.
Step 3: Check status
To determine whether the optimization has finished:
POST /api/db/job/read/findStatus
Content-Type: application/json
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "my-tenant-123"
}
Look for a status with statusDescription equal to SUCCESS_WITH_SOLUTION or ERROR.
Step 4: Retrieve the result (no client secret — covers both unencrypted and KMS)
If you did not provide a secret during submission, retrieve the result without one. This works regardless of whether the server applied KMS encryption or stored the data unencrypted — the server detects the encryption mode from the stored metadata and decrypts transparently.
POST /api/db/job/read/findOptimization
Content-Type: application/json
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "my-tenant-123",
"timeOut": "PT1M"
}
The response contains the full RestOptimization object with the computed solution, route assignments, scheduling details, and violation reports.
Step 5: Retrieve the result (with client secret — CLIENT mode only)
If a non-empty secret was provided in the persistenceSetting during submission, you must include the same secret in the DatabaseJobItemSearch request body:
{
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "my-tenant-123",
"secret": "YourStr0ng!Secret_Here",
"timeOut": "PT1M"
}
The server uses the secret together with the stored salt and IV to re-derive the AES key and decrypt the result. If the secret is missing, incorrect, or does not match the one used during submission, the server returns an error indicating that the file is corrupt or the secret was not provided.
Encryption at Rest
Job Mode supports three encryption modes for the optimization result payload. The mode is determined automatically at submission time based on a simple priority rule.
Encryption mode priority
- Client secret is non-empty → CLIENT mode (client manages the key, KMS is ignored even if enabled)
- No client secret + KMS is enabled for the tenant → KMS mode (server manages the key transparently)
- No client secret + no KMS → No encryption (data is compressed only)
The secret field in persistenceSetting.mongoSettings is the switch: provide a passphrase and you control the key; leave it empty and the server decides based on its KMS configuration.
CLIENT mode — Client-Managed Secret
This is the explicit encryption mode where the client provides and manages the passphrase.
During submission:
- The client includes a non-empty
secretin thepersistenceSetting.mongoSettings.secretfield. - The server validates the secret strength. If it is too weak, the job is rejected with HTTP 400.
- A random 16-byte salt and 12-byte IV are generated.
- A 256-bit AES key is derived from the secret using PBKDF2 (salt, 310,000 iterations).
- The optimization result is serialized, compressed with bzip2, and encrypted with AES-256-GCM using the derived key and IV.
- The encrypted bytes are stored in GridFS.
- The IV, salt, algorithm names, iteration count, and key length are stored in the GridFS metadata
secblock withencMode: "CLIENT". - The secret is discarded from server memory. It is never persisted.
During retrieval:
- The client provides the same
secretin theDatabaseJobItemSearch.secretfield. - The server reads the
secblock from the GridFS metadata and seesencMode: "CLIENT". - The AES key is re-derived using the stored salt, iteration count, and the provided secret.
- The ciphertext is decrypted with AES-256-GCM using the re-derived key and the stored IV.
- If the authentication tag does not match (wrong secret, tampered data), decryption fails and the server returns an error.
- On success, the decrypted bytes are decompressed (bzip2) and deserialized into the
RestOptimizationresponse.
If you lose the secret: The data cannot be recovered. There is no server-side copy of the secret, no master key, and no administrative backdoor. This is by design — it guarantees that only someone who knows the original passphrase can read the optimization result. Store your secrets in a secure location (e.g. a secrets manager or password vault).
Secret strength validation
When a non-empty secret is provided, the server validates it before accepting the job. The secret must meet minimum requirements for length and character class diversity (mixing uppercase, lowercase, digits, and special characters). If the secret is too weak, the submission is rejected immediately with HTTP 400 Bad Request — the optimization is never started.
CLIENT mode algorithm details
| Component | Algorithm / Parameter |
|---|---|
| Cipher | AES-256 in GCM mode (AES/GCM/NoPadding) |
| Key derivation | PBKDF2 with HMAC-SHA256 (PBKDF2WithHmacSHA256) |
| Iteration count | 310,000 (OWASP 2024 recommendation) |
| Key length | 256 bits |
| IV (Initialization Vector) | 12 bytes (96 bits), randomly generated per job, per NIST SP 800-38D |
| Salt | 16 bytes, randomly generated per job |
| Authentication tag | 128 bits (built into GCM mode) |
Why AES-GCM? GCM provides authenticated encryption — if anyone tampers with the encrypted data in MongoDB, decryption fails with an authentication error rather than silently producing corrupted output.
Why PBKDF2? The client provides a human-chosen passphrase, not a raw cryptographic key. PBKDF2 stretches this passphrase through 310,000 iterations of HMAC-SHA256 to produce a 256-bit AES key, making brute-force attacks computationally expensive.
Why random IV and salt per job? Even if two different jobs use the same passphrase, the randomly generated salt produces a different derived key, and the randomly generated IV ensures different ciphertext. This prevents pattern analysis across jobs.
KMS Envelope Encryption
When the server has a KMS (Key Management Service) configured and the client does not provide a secret, the server automatically encrypts the optimization result using envelope encryption. This is completely transparent to the client — the API request and response look identical to an unencrypted job.
How KMS mode works
Instead of deriving a key from a client passphrase, the server generates a random 256-bit AES key (the data encryption key, or DEK) for each job. The result is encrypted with this DEK. The DEK itself is then encrypted ("wrapped") by a key encryption key (KEK) managed in an external KMS (e.g. Azure Key Vault). The wrapped DEK is stored in the GridFS metadata. The plaintext DEK is discarded from memory.
On retrieval, the server reads the wrapped DEK from the metadata, unwraps it via the KMS, decrypts the result, and returns it. The client never sees the DEK or interacts with the KMS.
KMS mode end-to-end flow
During submission (encryption):
- The client submits a job with
secret: ""(empty) or omits the field entirely. - The server detects that KMS is enabled for this tenant.
- A random 256-bit AES key (DEK) and a random 12-byte IV are generated.
- The optimization result is serialized, compressed with bzip2, and encrypted with AES-256-GCM using the DEK and IV.
- The encrypted bytes are stored in GridFS.
- The DEK is wrapped (encrypted) by the tenant's KEK in the external KMS.
- The wrapped DEK, the KEK identifier, the IV, and
encMode: "KMS"are stored in the GridFS metadatasecblock. - The plaintext DEK is discarded from server memory. Only the wrapped DEK is persisted.
During retrieval (decryption):
- The client requests the result with no secret — just
jobIdandtenantId. - The server reads the
secblock from the GridFS metadata and seesencMode: "KMS". - The wrapped DEK is sent to the KMS for unwrapping using the KEK identified by
kekId. - The KMS returns the plaintext DEK.
- The ciphertext is decrypted with AES-256-GCM using the unwrapped DEK and the stored IV.
- On success, the decrypted bytes are decompressed and returned as the
RestOptimizationresponse. - The plaintext DEK is discarded from memory again.
KMS mode algorithm details
| Component | Algorithm / Parameter |
|---|---|
| Cipher | AES-256 in GCM mode (AES/GCM/NoPadding) — same as CLIENT mode |
| DEK generation | KeyGenerator.getInstance("AES") with 256-bit key length and SecureRandom |
| DEK wrapping | RSA-OAEP with SHA-256 (RSA/ECB/OAEPWithSHA-256AndMGF1Padding) via the external KMS |
| Key length | 256 bits |
| IV | 12 bytes (96 bits), randomly generated per job |
| Authentication tag | 128 bits (built into GCM mode) |
No PBKDF2 is involved in KMS mode — the DEK is already a proper 256-bit cryptographic key, not a human passphrase, so key derivation is unnecessary.
Why KMS mode?
- Zero client effort. The client doesn't need to manage, store, or remember any secrets. Encryption is invisible.
- Key rotation. The server operator can rotate the KEK in the KMS without re-encrypting existing data — old wrapped DEKs remain valid as long as the old KEK version is retained.
- Tenant offboarding. Deleting a tenant's KEK in the KMS makes all their data permanently unreadable — a clean, cryptographic guarantee.
- Audit trail. Cloud KMS services (Azure Key Vault, AWS KMS) provide detailed logs of every wrap/unwrap operation.
- HSM-backed security. In production, KEKs can be stored in FIPS 140-2 Level 2 (or higher) hardware security modules.
The tradeoff
With KMS mode, the server operator can decrypt the data (since the server has access to the KMS). If a client requires that even the server operator cannot read their data, they should use CLIENT mode and manage their own secret.
Server configuration
KMS mode is configured server-side. The client does not need to know or change anything.
| Property | Description | Example |
|---|---|---|
touroptimizer.security.kms.provider | Selects the KMS implementation. local for development, azure for production. Absent or none disables KMS. | local |
For local development and testing, the local provider generates RSA-2048 key pairs in memory per tenant. Keys are lost on server restart — data encrypted during one session cannot be decrypted after a restart. This is intentional for testing purposes.
For production (Azure Key Vault), the azure provider uses DefaultAzureCredential and the CryptographyClient from the Azure SDK. Each tenant is mapped to a KEK stored in Azure Key Vault. The required Azure RBAC role on the keys is Key Vault Crypto User (wrap/unwrap only — no key deletion or creation).
Encryption Mode Summary
The following table summarizes how the three modes differ from the client's perspective:
| No Encryption | CLIENT Mode | KMS Mode | |
|---|---|---|---|
secret in request | "" (empty) | Non-empty passphrase | "" (empty) |
| Who manages the key | Nobody | Client | Server (via KMS) |
| Encrypted at rest | No (bzip2 only) | Yes (AES-256-GCM) | Yes (AES-256-GCM) |
| Secret needed to retrieve | No | Yes (same passphrase) | No (transparent) |
_contentType in metadata | application/x-bzip2 | application/octet-stream | application/octet-stream |
sec.encMode in metadata | (no sec block) | CLIENT | KMS |
| Server can decrypt | Always | Only with client's passphrase | Always (has KMS access) |
| Data recoverable if key lost | Always | No | Yes (as long as KEK exists in KMS) |
In all three modes, metadata is always stored unencrypted and stream data (progress, status, warnings, errors) is always stored as unencrypted plain text.
What Gets Stored in MongoDB
Each job-mode optimization produces the following documents in MongoDB, all tagged with jobId and tenantId:
GridFS (result snapshot)
The full optimization result (compressed, optionally encrypted) is stored in GridFS. The metadata contains all the fields needed for querying, status checking, and decryption.
Unencrypted example (no secret, no KMS):
{
"metadata": {
"_contentType": "application/x-bzip2",
"creator": "PUBLIC_CREATOR",
"createdTimeStamp": 1774210149597,
"ident": "JOpt-Run-1774127074120",
"type": "OptimizationConfig<JSONConfig>",
"expireAt": "2026-03-24T20:09:09.626Z",
"status": {
"statusDescription": "SUCCESS_WITH_SOLUTION",
"error": "NO_ERROR",
"status": "SUCCESS_WITH_SOLUTION"
},
"jobId": "696c31c3-f419-4918-8a65-faf1f769d460",
"tenantId": "123456",
"compression": "bzip2",
"encrypted": false
}
}
CLIENT mode example (non-empty secret provided):
{
"metadata": {
"_contentType": "application/octet-stream",
"creator": "PUBLIC_CREATOR",
"createdTimeStamp": 1774131229940,
"ident": "JOpt-Run-1774127074120",
"type": "OptimizationConfig<JSONConfig>",
"expireAt": "2026-03-23T22:13:50.593Z",
"status": {
"statusDescription": "SUCCESS_WITH_SOLUTION",
"error": "NO_ERROR",
"status": "SUCCESS_WITH_SOLUTION"
},
"sec": {
"encMode": "CLIENT",
"iv": "dPrQge5LIDdPxEeg",
"salt": "UVSGQfW40PybJ2HecBhjmg==",
"encAlgo": "AES/GCM/NoPadding",
"secretKeyFacAlgo": "PBKDF2WithHmacSHA256",
"secretKeySpecAlgo": "AES",
"iterationCount": 310000,
"keyLength": 256
},
"jobId": "648d2724-3a77-47f4-b937-d3ab6abf2341",
"tenantId": "123456",
"compression": "bzip2",
"encrypted": true
}
}
KMS mode example (empty secret, KMS enabled on server):
{
"metadata": {
"_contentType": "application/octet-stream",
"creator": "PUBLIC_CREATOR",
"createdTimeStamp": 1774309926039,
"ident": "KMS-Test-Run",
"type": "OptimizationConfig<JSONConfig>",
"expireAt": "2026-03-25T23:52:06.831Z",
"status": {
"statusDescription": "SUCCESS_WITH_SOLUTION",
"error": "NO_ERROR",
"status": "SUCCESS_WITH_SOLUTION"
},
"sec": {
"encMode": "KMS",
"iv": "lJYEnGQoDJnG1TEE",
"encAlgo": "AES/GCM/NoPadding",
"keyLength": 256,
"salt": "",
"secretKeyFacAlgo": "",
"secretKeySpecAlgo": "AES",
"iterationCount": 0,
"wrappedDek": "u1ndsoDeGw3P494Jn3XU405Mr+g9EkBy...8A==",
"kekId": "local-kms://keys/tenant-abc-123"
},
"jobId": "a299d547-7db9-40aa-856e-e338c9d08593",
"tenantId": "tenant-abc-123",
"compression": "bzip2",
"encrypted": true
}
}
Notice the key differences across the three modes: _contentType distinguishes compressed from encrypted data. The sec block is absent for unencrypted data, contains PBKDF2 fields for CLIENT mode, and contains wrappedDek + kekId for KMS mode. The encrypted flag provides a quick boolean check without parsing the sec block.
Stream collections (progress, status, warning, error)
Each stream document also carries jobId and tenantId, enabling the job-based read endpoints to filter directly. Stream persistence is controlled by the streamPersistenceStratgySetting in the persistenceSetting — if saveProgress is false, no progress documents are written.
Persistence Settings
The persistenceSetting in the request body controls what gets saved, whether encryption is active, and for how long data is retained. The configuration is identical to classic FAF:
"persistenceSetting": {
"mongoSettings": {
"enablePersistence": true,
"secret": "",
"expiry": "PT48H",
"optimizationPersistenceStratgySetting": {
"saveOnlyResult": false,
"saveConnections": false
},
"streamPersistenceStratgySetting": {
"saveProgress": true,
"cycleProgress": true,
"saveStatus": true,
"cycleStatus": true,
"saveWarning": true,
"saveError": true
}
}
}
The secret field determines the encryption mode: set it to a strong passphrase for CLIENT mode, or leave it as "" to let the server use KMS (if enabled) or store without encryption. A non-empty client secret always takes priority over KMS.
For a detailed explanation of each field, see the Understanding the OptimizationPersistenceSetting object section in the classic FAF tutorial.
Error Handling
| HTTP Status | Meaning |
|---|---|
| 202 Accepted | Job was accepted and is running asynchronously. |
| 400 Bad Request | Invalid input or weak encryption secret (does not meet strength requirements). |
| 401 Unauthorized | License not valid, element limit exceeded, X-Tenant-Id header missing, jobId/tenantId mismatch on read, or missing client secret for CLIENT-mode encrypted data. |
| 500 Internal Server Error | A problem occurred during optimization startup, database read, or KMS communication failure. |
| 504 Gateway Timeout | The optimization exceeded the configured timeout. |
When an optimization fails asynchronously (after the 202 was already returned), the error is persisted to the database. The client discovers it by polling findStatus (which will show ERROR) or findError (which contains the error message). The findOptimization endpoint will return the error result snapshot with the optimizationStatus set to ERROR and the error message in the error field.
Agreement
For reading our license agreement and for further information about license plans, please visit www.dna-evolutions.com.
Authors
A product by dna-evolutions ©
