What a remote client cannot do
Everything an in-process SDK gives you that a caller on the network door does not, gathered in one place before you build against it.
Everything an in-process SDK gives you that a caller on the network door does not, gathered in one place before you build against it.
Every other page in this tier argues for the door. This one is the bill.
None of it is a gap waiting to be closed — each line is a decision recorded in
the .proto itself, under the heading "what this service deliberately does not
offer, and will not grow". Read it before you design against the door, not
after; a few of these change what your caller has to do rather than merely what
it can expect.
| An SDK | This door | Why |
|---|---|---|
| Registers tasks, so a typo is a startup error | Takes a task name as a string | The server holds no task registry. An unimplemented name enqueues fine and dead-letters later |
| Runs middleware around the enqueue | Runs none | Middleware is code in your process; there is no process here |
| Runs the worker too | Enqueues onto a queue somebody else drains | The other half is an executor, and a separate credential |
| Reaches the whole admin surface | Reaches what an inspect or admin token opens | Queues, dead letters, workers, periodic tasks and overrides are the admin door, behind scopes a producer token never carries. Token minting needs the separate tokens scope and never widens a grant; settings and webhook secrets stay behind the dashboard's session and role check |
| Chooses its namespace in your own configuration | Is fixed to one at mint time | The namespace comes from the credential, and no RPC in either package has a field for it. A read for a job in another namespace is indistinguishable from a job that does not exist |
| Decodes a result for you | Hands you bytes | Job.result is the tagged envelope; assert your decoder against wire-vectors.json once |
| Awaits completion in process | Watches for it | WatchJobs streams a job's transitions and closes once it is terminal. A job another process finishes arrives within the server's reconcile interval. See Watching jobs |
Four more that hold for an SDK too, but that a network caller meets sooner because it is the one writing the retry loop:
priority and scheduled_at influence dispatch. Nothing
promises two jobs enqueued in order run in order.unique_key dedupes an enqueue, not a run.EnqueueBatchResponse per item.NOT_FOUND does not mean the job never existed.UNAVAILABLE, DEADLINE_EXCEEDED and CANCELLED on an Enqueue may all
mean the write landed and the connection dropped afterwards, and no field on
the wire can tell you which. A client that retries sets a unique_key —
one per item for EnqueueBatch — and neither is retried for you.
That key dedupes against the active job, so once the original completes or dead-letters it is released and the same request enqueues a second job. Your total retry deadline has to be shorter than the job's own life.
An attached executor holds no database credential. It never reads a job row, never writes a result, and never resolves its own namespace, owner or attempt — the scheduler applies every one of those from the dispatch it recorded. That is exactly what makes it a door an application container may dial out through, and it is also the source of every limit below.
produce-scoped
credential of its own.flexiq.v1 and nothing
else, so this door needs a real gRPC library.hello carries tasks; the
scheduler derives the fingerprint from it, rather than trusting a second copy
of one fact that is free to disagree with the first.produce opens flexiq.v1, and read opens only its read-only methods.
execute opens flexiq.executor.v1. inspect and admin split
flexiq.admin.v1 between its read-only methods and the rest, and tokens
opens its token-management methods. produce covering
read is the one overlap. A token that can poll for work cannot enqueue it. A
token that can read the dead-letter queue cannot replay it. The refusal is
PERMISSION_DENIED with the reason SCOPE_DENIED, carrying the scope it
lacked. Grant each only to something that genuinely needs it. A produce,
read or execute grant can also be narrowed to some queues and tasks. API
tokens covers that and the token lifecycle.
Not losses — differences that surprise a reader who assumes the door is a thin wrapper over the SDK.
structured arguments refuse rather than round. Integers past
±9007199254740991, non-finite numbers and byte strings have no JSON form, so
the call is rejected with INVALID_ARGUMENT. What it does normalise is
object key order, which moves the bytes an auto: idempotency key hashes —
set unique_key yourself.
Two doors for one payload
has the whole of it.FLEXIQ_GRPC_EXECUTOR_STREAM_MAX_AGE. The scheduler drains the executor
before ending one, so nothing in flight is lost — but a client that logs a
rotation as a failure will page someone at 30-minute intervals.FLEXIQ_GRPC_TLS_CERT/
_TLS_KEY to terminate TLS in process
(TLS and mTLS), or put a proxy or a
service mesh in front instead. Either way it covers both doors, since they
share the one listener.Retries, timeouts, rate limits, circuit breakers, priorities, unique keys, debouncing, workflows and durable steps all work exactly as they do for an in-process caller, because they are properties of the job and the scheduler rather than of the door it arrived through. Those live in the SDK trees: Reliability is the entry point.