Chapter 20 Key Takeaways: Event-Driven Architecture with COBOL
Core Architectural Shift
From request/reply to publish/subscribe inverts the communication model. Instead of "System A asks System B to do something and waits," it becomes "System A announces that something happened, and any system that cares reacts independently." The producer doesn't know or care who the consumers are. Adding a new consumer is a configuration change (one subscription definition), not a code change.
Three Tools for Event-Driven COBOL
1. MQ Triggers — React to Messages
- MQ triggers automatically start COBOL programs when messages arrive on a queue
- TRIGTYPE(FIRST): Fires once when the first message arrives on an empty queue. The triggered program must drain all messages. Standard choice for high-volume queues.
- TRIGTYPE(EVERY): Fires for every message. Only for low-volume queues — will overwhelm CICS on high-volume queues.
- TRIGTYPE(DEPTH): Fires when queue depth reaches a threshold. For batch-oriented triggered processing.
- CKTI is the CICS trigger monitor that reads the initiation queue and starts transactions
- Triggered programs use EXEC CICS RETRIEVE to get the trigger message and discover the queue name
2. CICS Event Processing — Capture Without Code Changes
- EP intercepts CICS API commands at runtime and emits events through adapters (MQ, HTTP, TS Queue)
- Event bindings are XML configuration deployed as CICS bundles — no code compilation, no application modification
- EP can capture FILE operations, LINK/XCTL, START, and other CICS commands
- EP cannot capture pure COBOL logic (no EXEC CICS interception point)
- Default EP emission is asynchronous — not part of the application's unit of work (phantom events possible)
3. MQ Pub/Sub — Broadcast to Multiple Consumers
- Topics are hierarchical (forward-slash delimited):
CNB/EVENTS/WIRE/SUBMITTED #wildcard matches zero or more levels;+matches exactly one level- Durable subscriptions survive disconnections and restarts — required for production financial systems
- Non-durable subscriptions exist only while connected — monitoring and dev only
- Administrative subscriptions (created by MQ admin) are preferred over programmatic subscriptions for operational visibility
- Publishing from COBOL uses MQOT-TOPIC in the MQOD; the MQPUT call itself is identical to queue-based PUT
Event Schema Design Rules
- Every event has a header: version, type, ID, timestamp, source system, correlation ID
- Semantic versioning: Major changes break compatibility. Minor changes add fields only.
- Never remove or redefine fields within a major version
- Self-describing events: Include all data the consumer needs — don't force database lookups
- FILLER fields (20%+) in COBOL copybooks for forward compatibility
- Correlation ID in every event for end-to-end tracing
- Maintain an event catalog — registry of all event types, schemas, producers, and consumers
Event-Driven Patterns
| Pattern | Use When | Mainframe Implementation |
|---|---|---|
| Event Sourcing | Immutable audit trails, point-in-time reconstruction | Event stream as source of truth; materialized DB2 views for fast reads |
| CQRS | Write model and read model need different optimizations | Normalized write tables + denormalized read tables, bridged by events |
| Saga | Distributed transactions across systems without 2PC | Saga coordinator program with state in DB2, compensating actions for rollback |
| Idempotent Consumer | Always (MQ provides at-least-once, not exactly-once) | Event log table checked before processing, in the same unit of work |
| Circuit Breaker | Consumer connecting to an unreliable downstream service | Failure count tracking, three states (closed/open/half-open), configurable cooldown |
Production Rules
- TRIGTYPE(FIRST) for high-volume queues. Always. TRIGTYPE(EVERY) on a high-volume queue will crash your CICS region.
- Drain the queue in a triggered program. Process messages until MQGET returns 2033. Use a short wait interval (5 seconds) to catch messages that arrive during processing.
- Monitor CKTI health. If the initiation queue depth is growing, CKTI is either not running or not keeping up.
- Every subscription queue gets depth monitoring. Alert at 80% of MAXDEPTH. No exceptions.
- Durable subscriptions for production. Non-durable subscriptions lose messages when the subscriber disconnects.
- Idempotent consumers. Always. Check the event log before processing. Log and process in the same UOW.
- MQPMO-SYNCPOINT for critical events. The event and the business operation must commit or roll back together.
- Monitor the DLQ for event messages. A DLQ entry is a failed business event, not just a failed message.
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| TRIGTYPE(EVERY) on high-volume queue | CICS region hits MAXT, SOS, cascading abends | TRIGTYPE(FIRST), drain the queue |
| Triggered program processes one message and exits | Queue messages sit unprocessed until next trigger cycle | Process all messages until MQGET returns 2033 |
| No idempotency in event consumers | Duplicate events cause duplicate business processing (double debits, double notifications) | Event log table, check before processing |
| Asynchronous EP for transactionally critical events | Phantom events emitted for rolled-back transactions | Application-level MQPUT under syncpoint |
| Non-durable subscriptions in production | Messages lost when subscriber disconnects for maintenance | DURABLE(YES) on all production subscriptions |
| No subscription queue monitoring | Queue fills silently, events lost to DLQ | Depth monitoring with alerts on every subscription queue |
| God Event (200 fields in one event) | Every consumer coupled to every field; schema changes affect everyone | Domain-specific events with focused payloads |
| Topic explosion (per-branch, per-currency topics) | Unmanageable subscription count | Hierarchical topics with wildcard subscriptions; filter on content |
| Saga without persistent state | Saga cannot resume after crash; orphaned partial transactions | Saga state in DB2, committed with each step |
| Event sourcing without snapshots | State reconstruction time grows unbounded | Periodic snapshots to bound replay to a fixed interval |
Architecture Decision: Event-Driven vs. Request/Reply
Use Event-Driven (Pub/Sub) When: - Multiple consumers need the same data - The producer doesn't need a response before continuing - You need to add consumers without modifying the producer - Different consumers process at different speeds - Audit logging, analytics, and monitoring are needed alongside primary processing
Use Request/Reply When: - The sender needs a response before proceeding (authorization, balance inquiry) - There is exactly one consumer - The interaction is inherently synchronous (ATM: dispense cash only after approval) - Strong transactional coupling is required between request and response
At CNB, ~30% of flows converted to event-driven. ~70% remained request/reply. The skill is knowing which flows belong in which model.
Looking Ahead
This chapter gave you the event-driven toolkit: MQ triggers for reactive processing, CICS EP for non-invasive event capture, pub/sub for multi-consumer distribution, and event schemas for sustainable contracts. Chapter 21 extends these patterns to the API world — exposing mainframe events through API gateways, webhooks, and z/OS Connect so that systems outside the mainframe can participate in the event-driven architecture. Chapter 22 completes the integration picture with data integration patterns that combine file-based, message-based, and API-based feeds.