Skip to main content
Wildo.ai Coming soon

Files and storage

Keep large inputs out of queue messages

Large queued inputs can be stored in an internal payload resource and referenced by ID, with compression and a finite retention period.

A worker receives a small reference to a larger temporarily stored job input.

Keep large inputs out of queue messages

A background job may need a substantial input without carrying all of it through the message broker. Wildo moves large serialized payloads into an internal store and puts their reference on the job.

The worker resolves the reference before invoking the operation. Smaller inputs stay inline, while compression and expiry reduce the cost of temporary payload storage.

Example — Queue a substantial batch of work

An operation receives a large collection of input records. Its queue message carries a payload-storage ID instead of repeating the full JSON body. The worker loads that input when it executes, so the broker message remains small.

For engineers

Wonder Todos’ knowledge-base question operation runs on a queue consumer while the caller waits for its answer. This is the operation declaration from knowledge-documents.resources-config.ts, with explanatory comments omitted:

[KnowledgeDocuments_Operations.ASK]: {
  serviceRuntimeMode: ResourceOperation_ServiceRuntimeMode.QUEUED,
  queueConfig: { timeoutMs: 30000 },
  variants: [
    {
      variantType: ResourceOperationVariantType.API_CALL,
      isDefault: true,
      roles: [CORE_ORG_ROLES.ORG_MEMBER],
      riskLevel: ResourceOperationRiskLevel.LOW,
      resourceOperationLike: CoreResourceOperation.CREATE,
      requestDto: AskKnowledgeBaseDto,
      customResponseDto: AskKnowledgeBaseResponseDto,
      customServiceImplementationModes: [ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL],
    },
  ],
},

The caller uses the operation’s normal API contract. The service registry routes QUEUED work through enqueueAndWait, and the queue runtime builds the job. The request and response DTOs remain the operation’s contracts; the 30-second setting limits how long the caller waits for a reply, not how long stored input survives or whether execution is cancelled.

This real operation illustrates queue authoring, not a claim that its questions exceed the storage threshold. For any operation using this queue path, payload size independently decides whether the input travels inline or by reference. There is no extra file field or storage-ID parameter for the caller to manage.

Let queue serialization choose the path

The queue service measures serialized UTF-8 bytes and stores inputs at or above 100 KiB outside the broker message. Its bigint-safe serializer can carry values such as money amounts. In queue.backend.service.ts, the first excerpt shows that choice. The second shows the matching read in job-executor.backend.service.ts; comments are omitted from both.

let inputDataJson = inputData !== undefined ? ResourceSerializationUtils.stringifyWithBigInt(inputData) : undefined;
let inputPayloadStorageId: string | undefined;

if (inputDataJson && this.payloadStorage.shouldStore(inputDataJson)) {
  inputPayloadStorageId = await this.payloadStorage.store(inputData);
  inputDataJson = undefined; // Don't embed in message
  this.logDebug('Large payload stored externally', { inputPayloadStorageId });
}
let inputData: unknown;
if (job.inputPayloadStorageId) {
  inputData = await this.payloadStorage.retrieve(job.inputPayloadStorageId);
  this.logDebug('Retrieved external payload', {
    jobId: job.jobId,
    storageId: job.inputPayloadStorageId,
  });
} else if (job.inputDataJson) {
  inputData = JSON.parse(job.inputDataJson);
}

Follow the same input across the queue boundary

Serialized inputPublished jobWorker input
Below 102,400 UTF-8 bytesinputDataJson contains the JSON.Parsed directly from the job.
At least 102,400 UTF-8 bytesinputPayloadStorageId identifies the stored payload; inline JSON is omitted.Retrieved, decompressed if needed, then parsed.

The test is byte length after serialization, not the number of records or JavaScript characters. For example, accented text can cross the threshold with fewer characters than ASCII text. Storage takes place before broker publication, so a successful enqueue and a completed operation are still different outcomes.

Understand the internal store

JOB_PAYLOAD_STORAGE is an internal repository-backed resource, not the file-upload object store. The payload service stores JSON, original byte size, compression metadata and an expiry. It tries gzip for payloads above 10 KiB and keeps it when the compressed bytes are less than 80% of the original size. The accepted compressed bytes are stored as a base64 string; that encoding adds overhead, so the 80% comparison is not a promise of a 20% reduction in the database value.

The worker reads a referenced payload, decompresses it when necessary and parses its JSON before dispatching to the job handler. A string serialized from a bigint does not automatically become a bigint through generic JSON.parse; the receiving operation’s schema and deserialization contract still matter.

Fit job timing within payload retention

Stored payloads default to a 24-hour lifetime, with TTL and cleanup handling on the internal resource. Queue retry policy does not extend that lifetime. A delayed job or retry can therefore outlive its input; choose scheduling and recovery behavior with that boundary in mind.

This mechanism is temporary transport storage, not a durable business archive. Keep the application record or another durable source when a job must be recoverable after payload cleanup, and pass a business identifier when the operation can safely read current state instead of retaining a large snapshot.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.