ADR-016: SDK outbound minimal¶
- Status: Accepted
- Date: 2026-05-14
- Tags: integration, sdk, workers
Context and Problem Statement¶
Workers necesitan SDK para conectarse al engine, activate jobs, complete/fail. Camunda tiene SDK rico con OutboundConnectorContext.bindVariables(Class<T>) que hace 3 cosas (deserialize + validate + replace secrets). ¿Build SDK con esa abstracción o más minimal?
Decision Drivers¶
bindVariablesmagic puede confundir (qué validation? qué secret provider?)- Simple > abstract para SDKs
- Users prefer explicit > implicit
- Polyglot SDK requires consistency
Considered Options¶
- Minimal SDK: client + worker base, sin magic
- Camunda-style SDK: bindVariables, secret providers, validators
- Multi-tier SDK: minimal base + optional helpers
- No SDK (users construyen sobre REST API directo)
Decision Outcome¶
Chosen option: Minimal SDK + optional helpers (option 3) porque: - Base mínima es portable across languages - Helpers opcionales para Java/TS/Python - Users pueden opt-in o usar REST directo - No magic, no surprises
Positive Consequences¶
- Easy to port a múltiples languages
- Explicit > implicit
- Onboarding rápido
- Debugging straightforward
Negative Consequences¶
- Boilerplate más visible
- Users implementan secret resolution themselves
- Sin element templates auto-generated
API design¶
Core SDK (minimal)¶
import { WorkflowClient, JobWorker } from '@mvp/sdk';
const client = new WorkflowClient({
endpoint: 'https://workflow.example.com',
apiKey: process.env.WORKFLOW_API_KEY
});
// Client operations
await client.deployments.create('process.bpmn');
const pi = await client.processInstances.create({
bpmnProcessId: 'order-approval',
variables: { orderId: '123' }
});
// Worker
const worker = new JobWorker({
client,
jobType: 'check-credit',
handler: async (job) => {
const { customerId } = job.variables;
const result = await checkCredit(customerId);
return { creditScore: result.score };
},
concurrency: 10,
timeout: 30000
});
await worker.start();
That's it. No magic.
Optional helpers¶
import { typedVariables } from '@mvp/sdk/helpers';
// Type-safe variables con Zod
const InputSchema = z.object({
customerId: z.string().uuid(),
amount: z.number().positive()
});
const worker = new JobWorker({
client,
jobType: 'check-credit',
handler: async (job) => {
const input = typedVariables(job, InputSchema);
// input.customerId tiene type string
// throws ValidationError si inválido
return { score: await check(input) };
}
});
Optional layer — users que NO quieren Zod pueden skip.
Idempotency helper¶
import { withIdempotency } from '@mvp/sdk/helpers';
const worker = new JobWorker({
client,
jobType: 'send-email',
handler: withIdempotency({
store: new RedisStore({ url: 'redis://...' }),
ttl: 86400
}, async (job) => {
await sendEmail(job.variables);
})
});
Recall ADR-007 — workers MUST be idempotent. Helper facilita.
Secret resolution¶
NO en core SDK. Users resuelven manualmente:
const worker = new JobWorker({
client,
jobType: 'call-api',
handler: async (job) => {
const apiKey = process.env.EXTERNAL_API_KEY; // env var
// OR use Vault/AWS SM SDK directly:
// const apiKey = await vault.read('secret/data/external-api');
return await callAPI(apiKey, job.variables);
}
});
Cada user usa su secret backend. SDK no asume.
Polyglot strategy¶
| Language | SDK status | Comments |
|---|---|---|
| TypeScript/JS | Primary | Most popular MVP target |
| Python | Tier 1 | Major language |
| Go | Tier 1 | Cloud-native |
| Java | Tier 2 | Camunda migrants |
| Rust | Tier 3 | Niche |
| Other | Use REST API | OpenAPI spec available |
OpenAPI spec del engine permite SDK generation automática para cualquier language.
NO incluir en SDK¶
- Element template generator (Web Modeler thing)
- Secret providers framework
- Inbound connector base classes (ADR-015 — skipped)
- Distributed tracing auto-instrumentation (via OTel)
- Custom serialization (JSON only)
Links¶
- concepts/job-worker-pattern — Pattern
- adrs/adr-007-at-least-once-idempotent-workers — Idempotency requirement
- adrs/adr-015-skip-inbound-connectors — Inbound complementario
- concepts/connector-sdk-architecture — Camunda's SDK (reference)