Start HereOrdered learning track

Runtime Contracts and Failure Boundaries

Learn AWS Containers and Serverless - Part 004

Membongkar runtime contract, lifecycle, timeout, retry, shutdown, idempotency, dan failure boundary untuk container dan serverless production workload di AWS.

23 min read4509 words
PrevNext
Lesson 0498 lesson track01–18 Start Here
#aws#containers#serverless#runtime+6 more

Part 004 — Runtime Contracts and Failure Boundaries

Part sebelumnya membedakan control plane dan data plane. Sekarang kita masuk ke level yang lebih dekat dengan aplikasi: runtime contract.

Runtime contract adalah jawaban terhadap pertanyaan:

“Ketika workload ini benar-benar dijalankan, lingkungan eksekusi menjanjikan apa, meminta apa dari aplikasi, dan akan melakukan apa saat terjadi gangguan?”

Ini bukan topik kosmetik. Banyak incident container/serverless terjadi bukan karena engineer tidak tahu cara membuat service, tetapi karena mereka salah memahami kontrak runtime:

  • Container tidak menangani SIGTERM, sehingga deployment membuat request terpotong.
  • Lambda handler tidak idempotent, sehingga retry menciptakan double charge.
  • SQS visibility timeout lebih pendek dari processing time, sehingga message diproses paralel.
  • Step Functions retry terlalu agresif, sehingga downstream outage diperparah.
  • Kubernetes readiness probe terlalu dangkal, sehingga traffic masuk sebelum aplikasi siap.
  • ECS health check tergantung dependency jauh, sehingga task sehat dianggap mati saat downstream lambat.

Engineer senior tidak hanya bertanya “bagaimana deploy?”. Ia bertanya “apa kontrak hidup-mati runtime ini?”.

1. Runtime Contract: Definisi Operasional

Runtime contract adalah perjanjian implisit/eksplisit antara platform dan aplikasi.

Platform menjanjikan:

  • Cara aplikasi dimulai.
  • Resource yang tersedia.
  • Cara aplikasi menerima traffic/event/job.
  • Cara platform memberi sinyal shutdown.
  • Kapan platform menganggap aplikasi sehat.
  • Bagaimana retry dilakukan.
  • Bagaimana timeout ditegakkan.
  • Bagaimana log/metric/traces dikumpulkan.
  • Bagaimana identity diberikan.

Aplikasi wajib memenuhi:

  • Start dengan deterministik.
  • Expose port/handler sesuai kontrak.
  • Menangani shutdown dengan aman.
  • Tidak melewati resource limit.
  • Menghasilkan health signal yang benar.
  • Idempotent terhadap retry/duplikasi jika platform bisa mengulang work.
  • Menghormati timeout/deadline.
  • Mengisolasi failure dependency.

Jika kontrak ini tidak jelas, aplikasi mungkin berjalan di happy path tetapi rapuh saat deployment, scaling, outage, atau retry.

2. Runtime Contract per Compute Model

Setiap compute model punya kontrak berbeda.

Compute ModelUnit RuntimeEntry PointStop SignalScaling UnitFailure Surface
ECS/FargateTask/containerContainer entrypoint/CMDSIGTERM lalu kill setelah grace periodTask countTask stop, health check, OOM, image pull, ALB target
ECS on EC2Task/container di host EC2Container entrypoint/CMDSIGTERM/agent/host lifecycleTask + EC2 capacityHost pressure, agent issue, placement, daemon dependencies
EKSPod/containerContainer commandSIGTERM + terminationGracePeriodPod replica + nodeProbe failure, eviction, CNI, scheduling, node drain
LambdaFunction invocationHandlerRuntime shutdown/freeze lifecycleConcurrent executionTimeout, throttling, init failure, retry, cold start
Step FunctionsState machine executionStartExecution / service triggerExecution stop/fail/succeedExecution/state transitionTask error, retry storm, stuck execution, timeout
EventBridgeEvent deliveryPutEvents/source eventN/A per event target deliveryEvent routing/deliveryPattern mismatch, target fail, retry/DLQ
App RunnerWeb service instanceSource/image service commandManaged service lifecycleInstance countHealth, startup, request timeout, networking
BatchJob/containerJob commandJob stop/timeoutJob attempt/array childRetry, capacity, dependency, exit code

Perbedaan ini menentukan desain aplikasi. Aplikasi Java HTTP service yang sangat baik di ECS belum tentu baik sebagai Lambda. Worker ECS yang aman belum tentu aman jika dipindah ke SQS-triggered Lambda karena retry dan batch semantics berubah.

3. Lifecycle: Lahir, Hidup, Mati

Semua runtime punya lifecycle. Bentuknya berbeda, tetapi pola umumnya sama:

Tugas engineer adalah memastikan transisi antar-state aman.

3.1 Startup

Startup bukan hanya “process menyala”. Startup berarti aplikasi telah mencapai kondisi minimum untuk menerima work.

Untuk HTTP service:

  • Config terbaca.
  • Secret tersedia.
  • Database connection pool siap atau lazy strategy jelas.
  • Migration compatibility terpenuhi.
  • Cache warmup tidak blocking terlalu lama.
  • Port listen.
  • Readiness endpoint benar.

Untuk worker:

  • Consumer siap membaca queue/stream.
  • Idempotency store tersedia.
  • Downstream client siap.
  • Batch size dan concurrency benar.
  • Poison message path tersedia.

Untuk Lambda:

  • Static initialization tidak terlalu berat.
  • Client SDK dibuat di global scope bila aman untuk reuse.
  • Handler tidak bergantung pada mutable global state yang tidak dikontrol.
  • Init failure terlihat jelas.

3.2 Serving

Saat serving, runtime contract berpusat pada bounded execution:

  • Berapa request/event/job diproses paralel?
  • Apa batas waktu per unit work?
  • Apa yang terjadi jika dependency lambat?
  • Apakah retry terjadi di caller, platform, atau aplikasi?
  • Apakah side effect aman bila work diulang?

3.3 Draining

Draining adalah fase transisi saat aplikasi tidak boleh menerima work baru, tetapi harus menyelesaikan work yang sedang berjalan jika masih aman.

Contoh:

  • ECS task deregister dari ALB target group.
  • Kubernetes Pod readiness false sebelum termination.
  • Worker berhenti mengambil message baru.
  • HTTP server menutup listener tetapi menunggu in-flight request.

3.4 Shutdown

Shutdown harus eksplisit.

Aplikasi harus:

  • Menerima signal.
  • Stop accepting new work.
  • Finish in-flight work atau fail fast dengan aman.
  • Flush logs/traces/metrics.
  • Close connection pool.
  • Release lock/lease.
  • Exit dengan code yang benar.

Aplikasi tidak boleh:

  • Mengabaikan signal.
  • Membuka work baru saat draining.
  • Memegang message tanpa memperpanjang visibility timeout.
  • Menulis side effect separuh jalan tanpa status recoverable.

4. Container Runtime Contract

Container terlihat seperti “process dalam image”, tetapi production contract-nya lebih kaya.

4.1 Entrypoint dan PID 1

Di container, proses utama sering menjadi PID 1. PID 1 punya perilaku signal handling khusus. Jika entrypoint shell script tidak meneruskan signal ke process Java/Node/Go, aplikasi tidak menerima SIGTERM.

Bad pattern:

ENTRYPOINT ["sh", "-c", "java -jar app.jar"]

Lebih baik:

ENTRYPOINT ["java", "-jar", "app.jar"]

Atau jika butuh wrapper, gunakan exec:

#!/usr/bin/env sh
set -e
exec java -jar app.jar

Kontraknya sederhana: platform memberi signal ke proses utama. Jika proses utama tidak meneruskannya, shutdown graceful gagal.

4.2 Exit Code

Exit code adalah bahasa antara aplikasi dan scheduler.

Exit CodeArti UmumDampak Scheduler
0Selesai suksesUntuk service long-running bisa dianggap stopped dan diganti
Non-zeroFailureTask/pod dianggap gagal, mungkin restart
137Killed, sering OOM/SIGKILLResource limit atau shutdown timeout
143SIGTERM diterimaNormal during termination jika graceful

Untuk long-running service, exit code 0 tidak selalu “baik”. Jika service keluar tanpa diminta, scheduler akan menggantinya. Yang penting adalah mengapa keluar dan apakah sesuai lifecycle.

4.3 Resource Limits

Container runtime memiliki CPU/memory contract.

Kesalahan umum:

  • JVM melihat memory host, bukan container limit, jika konfigurasi lama/salah.
  • Heap terlalu besar sehingga native memory/metaspace/thread stack tidak tersisa.
  • CPU limit terlalu rendah menyebabkan GC dan startup lambat.
  • Memory leak baru terlihat saat autoscaling atau traffic spike.

Untuk Java service, jangan hanya set -Xmx tinggi. Sisakan ruang untuk:

  • Metaspace.
  • Thread stacks.
  • Direct buffers.
  • JIT/code cache.
  • Native libraries.
  • TLS/network buffers.
  • Observability agents.

Prinsip:

container_memory > heap + metaspace + thread_stack + direct_memory + native_overhead + safety_margin

4.4 Health Contract

Health check bukan dekorasi. Ia menentukan routing dan replacement.

Bedakan:

CheckPertanyaanContoh
Liveness“Process masih hidup?”Deadlock detection, event loop stuck
Readiness“Boleh terima traffic sekarang?”DB pool ready, migration compatible, app warmed
Startup“Masih proses boot?”Slow Java startup, cache warmup

Health check buruk:

GET /health -> selalu 200

Health check lebih baik:

  • /live: process internal masih hidup.
  • /ready: siap menerima traffic utama.
  • /startup: bootstrapping belum selesai.

Tetapi jangan berlebihan. Jika readiness mengecek dependency jauh terlalu agresif, transient downstream slowness bisa membuat semua instance dikeluarkan dari load balancer dan memperburuk outage.

Readiness harus merepresentasikan kemampuan melayani request, bukan menjadikan service sebagai health proxy untuk seluruh dunia.

5. ECS/Fargate Runtime Contract

ECS task adalah unit scheduling. Dalam satu task bisa ada satu atau lebih container.

Kontrak penting:

  • Task definition menentukan image, CPU, memory, port, env, secret, IAM role, log driver.
  • ECS service menjaga desired count.
  • Task bisa dihentikan karena deployment, scaling in, health check gagal, OOM, capacity issue, atau user action.
  • Load balancer hanya mengirim traffic ke target yang healthy.
  • Fargate menghilangkan host management, tetapi tidak menghilangkan kontrak aplikasi.

5.1 Shutdown di ECS

Saat deployment atau scale-in, ECS menghentikan task. Aplikasi harus bisa menerima termination signal dan berhenti dengan aman.

Untuk HTTP service:

  1. Task mulai draining dari load balancer.
  2. Target tidak menerima request baru.
  3. In-flight request diberi waktu selesai.
  4. Container menerima shutdown signal.
  5. App flush telemetry dan exit.

Jika deregistration delay lebih pendek dari request duration, request bisa terputus. Jika shutdown handler terlalu lama, platform bisa kill process.

5.2 Worker di ECS

Worker ECS biasanya membaca SQS/Kafka/Kinesis atau job table.

Runtime contract worker:

  • Stop polling saat termination signal.
  • Selesaikan message yang sedang diproses jika masih dalam visibility timeout.
  • Perpanjang visibility timeout untuk work panjang.
  • Commit offset hanya setelah side effect aman.
  • Idempotent terhadap message yang diproses ulang.
  • Jangan mengambil batch besar jika shutdown window kecil.

Anti-pattern:

Worker menerima SIGTERM tetapi tetap polling message baru.

Akibat:

  • Deployment lama selesai lambat.
  • Message stuck.
  • Duplicate processing meningkat.
  • Scale-in berbahaya.

6. EKS Runtime Contract

EKS mengikuti kontrak Kubernetes.

Unit runtime adalah Pod. Pod memiliki satu atau lebih container, shared network namespace, optional volumes, lifecycle hooks, probes, dan termination grace period.

6.1 Probe Contract

Kubernetes memakai probes untuk mengambil keputusan:

  • Liveness gagal → container restart.
  • Readiness gagal → Pod dikeluarkan dari Service endpoint.
  • Startup probe belum sukses → liveness/readiness bisa ditunda.

Kesalahan umum:

  • Liveness mengecek dependency eksternal, sehingga pod restart saat DB lambat.
  • Readiness selalu 200, sehingga traffic masuk sebelum warmup selesai.
  • Probe timeout terlalu pendek untuk Java under GC pressure.
  • Initial delay asal-asalan, bukan berdasarkan startup distribution.

6.2 Termination Contract

Saat Pod dihentikan:

  1. Pod diberi deletion timestamp.
  2. Endpoint controller menghapus Pod dari endpoint Service.
  3. Kubelet menjalankan preStop hook jika ada.
  4. Container menerima SIGTERM.
  5. Grace period berjalan.
  6. Jika belum exit, SIGKILL.

Aplikasi harus selaras dengan terminationGracePeriodSeconds dan load balancer deregistration behavior.

6.3 Sidecar Contract

Sidecar memperumit lifecycle.

Contoh sidecar:

  • Service mesh proxy.
  • Log shipper.
  • Secrets agent.
  • Telemetry collector.

Pertanyaan penting:

  • Jika app container exit, apakah sidecar ikut exit?
  • Jika sidecar belum ready, apakah app boleh menerima traffic?
  • Jika proxy mati, apakah app masih bisa reach downstream?
  • Jika telemetry sidecar lambat, apakah shutdown tertahan?

Sidecar bukan gratis. Ia menambah dependency runtime di dalam Pod.

7. Lambda Runtime Contract

Lambda punya kontrak berbeda dari container service.

Unit runtime bukan process long-running yang menerima request lewat port. Unit runtime adalah invocation di dalam execution environment.

AWS Lambda execution environment lifecycle mencakup initialization, invocation, dan shutdown. Environment dapat digunakan ulang untuk invocation berikutnya, sehingga global state bisa bertahan, tetapi tidak boleh dianggap permanen.

7.1 Init Contract

Init terjadi sebelum handler memproses event.

Yang biasa dilakukan saat init:

  • Load classes/modules.
  • Membuat SDK clients.
  • Membaca env vars.
  • Membuat connection pool.
  • Load config.

Yang berbahaya saat init:

  • Network call lambat tanpa timeout.
  • Mengambil lock global.
  • Warmup data besar.
  • Membaca secret berkali-kali tanpa cache.
  • Inisialisasi framework terlalu berat untuk cold start budget.

Untuk Java Lambda, init sering menjadi sumber latency. SnapStart/provisioned concurrency bisa membantu pada kasus tertentu, tetapi desain dependency dan initialization tetap penting.

7.2 Invocation Contract

Handler menerima event dan context. Handler harus selesai sebelum timeout.

Pertanyaan wajib:

  • Apakah event bisa datang dua kali?
  • Apakah handler idempotent?
  • Apakah downstream call punya timeout lebih pendek dari Lambda timeout?
  • Apakah response error memicu retry platform?
  • Apakah batch partial failure didukung?
  • Apakah concurrency dibatasi agar downstream tidak hancur?

7.3 Global State Contract

Global state boleh menjadi cache optimisasi, bukan sumber kebenaran.

Aman:

  • Reuse SDK client.
  • Reuse DB connection dengan validasi.
  • Cache config dengan TTL.
  • Cache compiled regex/schema.

Berbahaya:

  • Menyimpan progress bisnis hanya di memory.
  • Menganggap cache selalu ada.
  • Menganggap satu execution environment hanya memproses satu tenant sepanjang hidup.
  • Menyimpan credential hasil assume role tanpa expiry handling.

7.4 Timeout Contract

Lambda timeout adalah batas keras untuk invocation. Jika function timeout, process bisa dihentikan tanpa aplikasi menyelesaikan cleanup normal.

Desain benar:

external_call_timeout < handler_remaining_time < lambda_timeout

Gunakan remaining time dari context untuk berhenti sebelum platform menghentikan paksa.

7.5 Concurrency Contract

Concurrency adalah jumlah execution yang berjalan paralel.

Lambda bisa scale cepat, tetapi downstream belum tentu mampu. Reserved concurrency bukan hanya performance setting; ia adalah bulkhead.

Contoh:

  • Lambda membaca SQS dan menulis database.
  • Traffic naik.
  • Lambda scale out.
  • Database connection habis.
  • Invocation error.
  • SQS retry.
  • Backlog naik.
  • Lambda makin banyak mencoba.

Solusi bukan selalu “naikkan concurrency”. Kadang perlu menurunkannya, menambah buffer, memperbaiki idempotency, dan mengatur batch/window.

8. Event Source Runtime Contract

Serverless sering dipicu event source. Kontraknya berbeda untuk tiap sumber.

SourceDelivery SemanticsFailure Concern
API GatewaySynchronous request/responseTimeout, mapping error, client retry
SQSAt-least-once queue deliveryDuplicate, visibility timeout, poison message
Kinesis/DynamoDB StreamsOrdered per shard/partition keyIterator age, blocking record, batch failure
EventBridgeEvent routing to targetsPattern, target retry, DLQ, duplicate event
SNSFanoutSubscriber failure, retry, filtering
S3 eventEvent notificationDuplicate/missing ordering assumptions
SchedulerTime-based triggerMissed/late execution, retry window

8.1 SQS + Lambda Contract

SQS event source mapping polls queue and invokes Lambda with batches.

Important variables:

  • Batch size.
  • Maximum batching window.
  • Visibility timeout.
  • Lambda timeout.
  • Partial batch response.
  • DLQ/redrive policy.
  • Reserved concurrency.

Invariant:

visibility_timeout > lambda_timeout + retry_safety_margin

Jika visibility timeout lebih pendek dari processing time, message bisa muncul lagi dan diproses paralel.

8.2 Stream Contract

Kinesis/DynamoDB Streams membawa ordering per shard/partition key. Satu bad record dapat menahan shard jika failure handling buruk.

Pattern:

  • Partial batch response jika tersedia.
  • Bisect batch on error.
  • Maximum retry/record age.
  • DLQ/destination untuk record gagal.
  • Monitor iterator age.

8.3 EventBridge Target Contract

EventBridge bisa mengirim event ke banyak target. Tiap target harus dianggap consumer independen.

Konsekuensi:

  • Satu event bisa memicu banyak side effect.
  • Target failure tidak boleh diasumsikan menggagalkan semua target lain.
  • Consumer harus idempotent.
  • Event schema harus stabil.
  • DLQ per target penting untuk recovery.

9. Step Functions Runtime Contract

Step Functions menjalankan state machine execution. Kontraknya bukan “function call biasa”, melainkan durable state transition.

9.1 Retry dan Catch

Step Functions menyediakan Retry dan Catch. Tanpa desain yang benar, retry bisa merusak downstream.

Retry policy harus menjawab:

  • Error apa yang retryable?
  • Berapa attempt?
  • Berapa interval?
  • Apakah exponential backoff?
  • Apakah ada jitter di level lain?
  • Apakah task idempotent?
  • Apakah retry masih berguna setelah deadline bisnis lewat?

Catch path harus menjawab:

  • Apakah perlu compensation?
  • Apakah error bisa diabaikan?
  • Apakah workflow harus fail?
  • Apakah perlu human review?
  • Apakah perlu event audit?

9.2 Task Timeout vs Workflow Timeout

Setiap Task bisa punya timeout. Workflow keseluruhan juga punya batas durasi sesuai jenis workflow.

Jangan membiarkan task menggantung tanpa timeout. Durable tidak berarti infinite.

9.3 Compensation Contract

Dalam saga, compensation bukan rollback database ajaib. Ia adalah aksi domain baru.

Contoh order workflow:

  1. Reserve inventory.
  2. Charge payment.
  3. Create shipment.

Jika payment gagal, compensation mungkin release inventory. Tetapi jika shipment sudah dibuat, compensation berbeda.

Setiap step harus punya:

  • Forward action.
  • Idempotency key.
  • Completion record.
  • Compensation action jika diperlukan.
  • Compensation idempotency.
  • Audit trail.

10. Failure Boundary

Failure boundary adalah garis di mana failure harus ditangkap, diterjemahkan, dibatasi, atau dipropagasikan secara sengaja.

Tanpa boundary, failure bocor dan menjadi cascading failure.

Boundary bisa berupa:

  • Process boundary.
  • Container boundary.
  • Pod boundary.
  • Task boundary.
  • Function invocation boundary.
  • Queue boundary.
  • Event bus boundary.
  • Workflow state boundary.
  • Database transaction boundary.
  • Tenant boundary.

Setiap boundary harus punya policy.

11. Timeout: Batas Waktu sebagai Desain

Timeout adalah salah satu kontrak paling sering disepelekan.

Tanpa timeout, sistem tidak tahu kapan harus menyerah. Dengan timeout buruk, sistem menyerah terlalu cepat atau terlalu lambat.

11.1 Timeout Hierarchy

Timeout harus membentuk hierarki dari luar ke dalam.

client_timeout
  > api_gateway_or_lb_timeout
    > service_request_timeout
      > downstream_call_timeout
        > database_statement_timeout

Jika downstream timeout lebih panjang dari caller timeout, work tetap berjalan setelah caller menyerah. Ini membuang kapasitas dan bisa menciptakan side effect terlambat.

11.2 Lambda Timeout

Lambda timeout harus cukup panjang untuk work normal, tetapi cukup pendek untuk mencegah stuck execution. Downstream timeout harus lebih pendek dari sisa waktu handler.

11.3 Queue Visibility Timeout

Visibility timeout harus lebih panjang dari processing time normal + retry margin. Jika tidak, message muncul lagi sebelum worker selesai.

11.4 Step Functions Timeout

Task timeout membuat workflow tidak menggantung. Workflow timeout memastikan proses tidak hidup melebihi nilai bisnisnya.

12. Retry: Obat yang Bisa Menjadi Racun

Retry memperbaiki transient failure. Retry juga bisa menghancurkan sistem yang sedang overload.

Retry aman jika:

  • Failure transient.
  • Operation idempotent.
  • Ada backoff.
  • Ada max attempt.
  • Ada retry budget.
  • Downstream punya kapasitas pulih.

Retry buruk jika:

  • Error permanent.
  • Payload invalid.
  • Auth denied.
  • Schema incompatible.
  • Downstream overload parah.
  • Side effect tidak idempotent.

12.1 Retry Layering

Dalam cloud architecture, retry bisa terjadi di banyak layer:

  • SDK client retry.
  • Application retry.
  • Load balancer/client retry.
  • Queue redelivery.
  • Lambda async retry.
  • EventBridge target retry.
  • Step Functions retry.
  • Database driver retry.

Jika semuanya aktif tanpa koordinasi, terjadi retry amplification.

Total attempt bisa menjadi 27 untuk satu user request.

12.2 Retry Budget

Retry budget membatasi total effort tambahan yang boleh dipakai.

Contoh policy:

  • Synchronous API: maksimal 1 retry di client, tidak ada retry panjang di server.
  • Async queue: retry boleh lebih banyak, tetapi dengan DLQ dan visibility timeout benar.
  • Workflow: retry eksplisit per state dengan backoff dan catch.
  • Payment operation: retry hanya untuk network timeout sebelum status unknown; setelah status unknown, lakukan reconciliation.

13. Idempotency: Syarat Hidup di Sistem At-Least-Once

Banyak sistem AWS memiliki delivery at-least-once atau retry behavior. Artinya aplikasi harus siap menerima work yang sama lebih dari sekali.

Idempotency berarti melakukan operasi yang sama berkali-kali menghasilkan efek akhir yang sama.

13.1 Idempotency Key

Key harus berasal dari domain/event, bukan random per attempt.

Contoh:

OperationIdempotency Key
Create orderorderId atau client request id
Charge paymentpaymentAttemptId
Process eventeventId + consumer name
Send notificationnotificationId
Reserve inventoryreservationId

13.2 Idempotency Store

Idempotency butuh penyimpanan.

Pattern:

  • Unique constraint di database.
  • DynamoDB conditional put.
  • Redis SETNX dengan TTL untuk short-lived operation.
  • Inbox table untuk consumed events.
  • Outbox table untuk produced events.

13.3 Status Unknown

Kasus paling sulit adalah timeout setelah side effect mungkin terjadi.

Contoh:

  • Service memanggil payment gateway.
  • Gateway timeout.
  • Payment mungkin berhasil atau gagal.
  • Retry charge bisa double charge.

Solusi:

  • Gunakan idempotency key ke payment provider.
  • Simpan operation status.
  • Reconcile dengan query status.
  • Jangan retry blind operation yang punya side effect finansial.

14. Backpressure dan Concurrency Boundary

Backpressure adalah kemampuan sistem menolak, menunda, atau memperlambat work ketika kapasitas tidak cukup.

Tanpa backpressure:

Dengan backpressure:

Boundary yang bisa dipakai:

  • Reserved concurrency Lambda.
  • Max concurrency event source mapping.
  • ECS desired/max task count.
  • Kubernetes HPA max replicas.
  • Worker semaphore.
  • Connection pool size.
  • Queue visibility/consumer count.
  • Rate limit per tenant.
  • Circuit breaker per downstream.

Concurrency bukan hanya throughput knob. Ia adalah reliability guardrail.

15. Failure Mode per Runtime

15.1 ECS/Fargate

FailurePenyebabMitigasi
Task stoppedCrash, exit, OOM, deploymentLogs, stopped reason, memory tuning, signal handling
Image pull gagalECR permission/network/tagExecution role, VPC endpoints/NAT, immutable tag
Health check gagalApp not ready, wrong pathProper readiness, startup delay, ALB config
Deployment stuckNew tasks unhealthyCircuit breaker, rollback, task event inspection
Scale out gagalQuota/IP/capacityQuota alert, subnet capacity, capacity provider strategy
Request cut during deployDrain misconfiguredDeregistration delay, graceful shutdown

15.2 EKS

FailurePenyebabMitigasi
Pending podNo node/resource/affinity/PVCCapacity planning, Karpenter, requests review
CrashLoopBackOffApp crash/configLogs, probes, config validation
ImagePullBackOffRegistry/IAM/networkECR auth, node role, VPC path
Readiness falseApp/dependency not readyProbe design, startup probe
EvictionNode pressureRequests/limits, node sizing, QoS
Webhook blocks deployAdmission dependency downFailurePolicy, HA webhook, break-glass

15.3 Lambda

FailurePenyebabMitigasi
TimeoutSlow dependency, too much workTimeout hierarchy, chunking, async workflow
ThrottlingConcurrency limitReserved concurrency planning, queue buffer
Cold startRuntime/package/initProvisioned concurrency, SnapStart, dependency diet
Async retry stormTarget/downstream failDLQ, destinations, concurrency cap
Duplicate side effectRetry/event duplicateIdempotency key/store
Batch poisonOne bad record fails batchPartial batch response, DLQ, bisect

15.4 EventBridge

FailurePenyebabMitigasi
Event not matchedPattern wrongContract tests, sample event replay
Target delivery failedPermission/throttle/errorTarget DLQ, retry policy, metrics
Schema breakProducer changed payloadSchema versioning, compatibility tests
Fanout side effect inconsistentSome targets succeed, others failConsumer idempotency, audit, replay strategy

15.5 Step Functions

FailurePenyebabMitigasi
Execution failedUncaught task errorCatch, compensation, domain error modelling
Retry stormAggressive retryBackoff, max attempt, downstream-aware policy
Execution stuckMissing callback/waitTimeout, heartbeat, watchdog
Compensation failedNon-idempotent compensationCompensation idempotency, manual repair path
Definition bugBad state transitionVersioning, test execution, canary workflow

16. Designing Runtime Contracts: A Template

Untuk setiap workload, isi template berikut.

Workload name:
Runtime model:
Entry point:
Unit of work:
Concurrency model:
Startup requirement:
Readiness condition:
Liveness condition:
Shutdown signal:
Drain behavior:
Timeout budget:
Retry owner:
Retry max attempts:
Idempotency key:
Idempotency store:
Backpressure mechanism:
Failure boundary:
DLQ/quarantine path:
Observability signal:
Rollback behavior:
Manual recovery path:

Contoh untuk ECS API:

Workload name: case-api
Runtime model: ECS Fargate service behind ALB
Entry point: java -jar app.jar
Unit of work: HTTP request
Concurrency model: Tomcat/Netty worker threads + DB pool
Startup requirement: config loaded, port listening, migration compatible
Readiness condition: app ready, DB pool can acquire connection within threshold
Liveness condition: JVM responsive, event loop not deadlocked
Shutdown signal: SIGTERM
Drain behavior: stop accepting new requests, finish in-flight within 25s
Timeout budget: client 5s, ALB 6s, service 4s, DB statement 2s
Retry owner: client for safe GET only; no blind POST retry without idempotency key
Idempotency key: X-Idempotency-Key for mutating operations
Backpressure: rate limit + DB pool + ALB target scaling
Failure boundary: per request
Observability signal: RED metrics, JVM, DB pool, ALB target health
Rollback behavior: ECS deployment rollback to previous task definition
Manual recovery path: replay outbox, repair failed case transitions

Contoh untuk Lambda SQS worker:

Workload name: case-event-consumer
Runtime model: Lambda triggered by SQS
Entry point: handler(event, context)
Unit of work: one SQS message
Concurrency model: Lambda concurrency capped by event source/reserved concurrency
Startup requirement: SDK clients initialized, idempotency table reachable
Readiness condition: N/A per invocation, init success required
Liveness condition: invocation completes before timeout
Shutdown signal: Lambda timeout/shutdown lifecycle
Drain behavior: N/A; message success/failure controls redelivery
Timeout budget: lambda 60s, downstream 5s each, stop at remaining time <10s
Retry owner: SQS redelivery + Lambda batch failure handling
Idempotency key: eventId + consumerName
Idempotency store: DynamoDB conditional write
Backpressure: reserved concurrency 20, queue backlog alarm
Failure boundary: per message with partial batch response
DLQ/quarantine path: SQS redrive to DLQ after maxReceiveCount
Observability signal: error, duration, iterator/backlog age, DLQ depth
Rollback behavior: Lambda alias back to previous version
Manual recovery path: redrive DLQ after fix

17. Testing Runtime Contracts

Runtime contract yang tidak diuji akan gagal di production.

17.1 Test Startup

  • Start container dengan env minimal.
  • Start tanpa secret wajib dan pastikan gagal cepat.
  • Start dengan dependency lambat.
  • Ukur startup distribution, bukan hanya single run.

17.2 Test Shutdown

  • Kirim SIGTERM ke process.
  • Pastikan tidak menerima work baru.
  • Pastikan in-flight selesai atau dibatalkan dengan status jelas.
  • Pastikan exit sebelum grace period.
  • Pastikan telemetry ter-flush.

17.3 Test Retry

  • Inject network timeout.
  • Inject 500 transient.
  • Inject 400 permanent.
  • Pastikan permanent error tidak di-retry membabi buta.
  • Pastikan idempotency mencegah double side effect.

17.4 Test Poison Message

  • Kirim payload invalid.
  • Pastikan satu message tidak memblokir seluruh batch/shard selamanya.
  • Pastikan DLQ punya informasi cukup untuk replay/debug.

17.5 Test Scaling Boundary

  • Naikkan traffic/queue backlog.
  • Pastikan autoscaling membaca sinyal benar.
  • Pastikan downstream tidak overload.
  • Pastikan scale-in tidak memotong work.

18. Observability untuk Runtime Contract

Setiap kontrak butuh signal.

ContractSignal
Startupstartup duration, init error, first readiness time
Readinessready/unready transition, target health, probe failure reason
Shutdowntermination count, drain duration, forced kill count
Timeouttimeout count, remaining time near zero, downstream latency
Retryretry attempts, retry reason, retry success ratio
Idempotencyduplicate detected, idempotency conflict, unknown status
Backpressurequeue age, rejected requests, throttles, concurrency saturation
MemoryOOM count, heap usage, GC pause, RSS
Deploymentold/new version error split, rollback count

Dashboard bagus menunjukkan lifecycle, bukan hanya CPU.

19. Production Review Checklist

Sebelum workload masuk production, jawab ini:

  1. Apa unit of work?
  2. Apa entry point?
  3. Apa sinyal readiness?
  4. Apa sinyal liveness?
  5. Bagaimana aplikasi menerima shutdown?
  6. Berapa grace period?
  7. Apa yang terjadi pada in-flight work saat shutdown?
  8. Apa timeout end-to-end?
  9. Siapa melakukan retry?
  10. Apa retry budget?
  11. Apakah operasi mutasi idempotent?
  12. Di mana idempotency disimpan?
  13. Apa concurrency maksimal?
  14. Apa downstream paling lemah?
  15. Apa backpressure mechanism?
  16. Apa DLQ/quarantine path?
  17. Bagaimana replay dilakukan?
  18. Apa metric yang membuktikan kontrak dipenuhi?
  19. Apa emergency brake?
  20. Apa rollback mengatasi side effect atau hanya code/config?

20. Common Anti-Patterns

20.1 “Platform Akan Mengurus Semuanya”

Fargate mengurus server. Lambda mengurus execution environment. Kubernetes mengurus scheduling. Tidak ada yang otomatis mengurus idempotency bisnis, timeout hierarchy, atau compensation logic.

20.2 “Health Check = Ping”

Ping hanya membuktikan process bisa menjawab ping. Production readiness butuh kontrak lebih spesifik.

20.3 “Retry Sampai Berhasil”

Retry tanpa batas adalah denial-of-service yang ditulis sendiri.

20.4 “Queue Menyelesaikan Scaling”

Queue hanya memindahkan tekanan dari synchronous ke asynchronous. Jika consumer/downstream tidak punya kapasitas, backlog tetap tumbuh.

20.5 “Rollback Menyelesaikan Semua”

Rollback code tidak menghapus message yang sudah dikirim, payment yang sudah dicoba, email yang sudah terkirim, atau state machine execution yang sudah berjalan.

20.6 “Cold Start Hanya Masalah Lambda”

Container juga punya cold start: image pull, JVM boot, dependency warmup, readiness delay, node scale-up. Istilah berbeda, efek sama: kapasitas baru belum langsung siap.

21. Mental Model Akhir

Runtime engineering adalah seni membuat aplikasi tahu bagaimana harus hidup dan mati di bawah platform tertentu.

Pikirkan dalam tujuh pertanyaan:

  1. Start — bagaimana workload dimulai?
  2. Ready — kapan boleh menerima work?
  3. Serve — bagaimana work diproses dengan batas waktu dan kapasitas?
  4. Fail — failure apa yang mungkin terjadi dan di boundary mana ditangkap?
  5. Retry — siapa yang mengulang dan apakah aman?
  6. Stop — bagaimana workload berhenti tanpa merusak state?
  7. Recover — bagaimana operator memperbaiki work yang gagal sebagian?

Jika tujuh pertanyaan ini tidak terjawab, sistem belum production-ready walaupun sudah deploy.

22. Ringkasan

Runtime contract adalah jembatan antara desain arsitektur dan perilaku nyata aplikasi.

Container/serverless production workload harus punya kontrak eksplisit untuk:

  • Entrypoint.
  • Startup.
  • Readiness.
  • Liveness.
  • Shutdown.
  • Timeout.
  • Retry.
  • Idempotency.
  • Concurrency.
  • Backpressure.
  • Failure boundary.
  • Observability.
  • Recovery.

ECS, EKS, Lambda, EventBridge, Step Functions, App Runner, dan Batch punya kontrak runtime yang berbeda. Engineer top-level tidak memindahkan workload antar compute model hanya karena “bisa jalan”. Ia mengevaluasi apakah kontrak runtime cocok dengan shape workload, failure semantics, dan operational model.

Dalam part berikutnya, kita akan menyusun reference architecture map: bagaimana API, worker, queue, event bus, workflow, registry, CI/CD, observability, dan governance disusun menjadi platform container/serverless production-ready.

23. Referensi

Lesson Recap

You just completed lesson 04 in start here. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.