Documentation — Architecture

# EBS & DB Operations

Not every operation is a query. Starting a service, stopping a Concurrent Manager, resetting a stuck Workflow Mailer — these are control-plane actions, and they run through two different transports depending on what kind of action it is.

## Two transports, one dashboard

Every EBS control action reaches your servers through the same outbound agent protocol described in Connectivity & Agent Protocol — no exceptions, no separate channel. What differs is which agent receives the command and how it's addressed:

Op type | Examples | Routes to
--- | --- | ---
Shell ops | Service status, Concurrent Manager start/stop, Apache/OHS, Node Manager | The app-tier agent directly, via `/api/ebs-ctrl` — a shell command runs locally under the applmgr user.
SQL ops | Running/failed concurrent requests, WF Mailer status and reset, OPP queue | The paired DB-tier connection — resolved from the app-tier connection first, then run as the APPS schema.
ADOP phase execution | Validate, Prepare, Apply, Actualize, Finalize, Cutover, Cleanup, FS Clone, Abort | The app-tier agent directly, via `/api/ebs-ops/middleware-run` — same shell-op transport as service start/stop, using the stored APPS password (SYSTEM/WebLogic when configured).

## How app-tier gets paired to DB-tier

An EBS environment usually has two TuneVault connections: one pointed at the application tier, one at the database tier. A SQL op initiated from the app-tier connection's dashboard needs to actually run against the database — so it has to find its sibling connection first.

routes/ebs-ops.js — findPairedDbConn()
SELECT id, host, port, service_name FROM oracle_connections WHERE ebs_instance_name = $1 AND user_id = $2 AND server_type IN ('db', 'both') ORDER BY server_type -- 'both' sorts after 'db'; prefer plain 'db' LIMIT 1

The pairing key is `ebs_instance_name` — both connections for one EBS environment are tagged with the same instance name when they're set up, and this is what lets TuneVault know "these two connections are the same environment." If no paired DB-tier connection exists, the SQL op has nowhere to run and fails cleanly rather than guessing at a target.

## Destructive ops require explicit confirmation

Starting or stopping a service isn't a read — it changes something running in production. Every destructive shell op requires a client-side CONFIRM step before the command is even sent to the agent. This isn't just a UI nicety: it means a single accidental click on the wrong button can't bounce a service, because the request never leaves the browser without the second, explicit confirmation.

## The ADOP gate: destructive ops are refused during a patch cycle

Oracle's Online Patching (ADOP) puts EBS into a distinct, sensitive state — patch edition switching, database DDL, and service restarts already in flight elsewhere. Bouncing a service or running certain SQL ops mid-cycle can corrupt the patch. TuneVault tracks this per connection:

Detecting an ADOP cycle and running one are two different capabilities, and TuneVault does both. As the table above shows, TuneVault can execute the ADOP phases itself. The gate described in this section is separate from and complementary to that: it refuses other ops during a detected patch cycle — preventing, for example, a service restart while TuneVault's own ADOP execution is mid-cycle. The `adop_*` phases are explicitly exempt from it; they are the patch cycle, so gating them on "a patch cycle is active" would refuse the very ops the gate exists to protect.
services/adop-detector.js
if (state.patching) { // op is blocked; phase is surfaced to the UI console.log(`patching=true phase=${state.phase}`); }

When `ebs_adop_state.patching` is true for a connection, destructive ops are refused server-side on both transports. On the shell path that means Concurrent Manager start/stop, Apache/OHS, OPMN, Apps Listener, Node Manager, WLS Admin, managed servers, WF Mailer, and Stop/Start All; on the database path it means session kills, instance shutdown/startup, PDB close, cache flushes, and stats gathers. The refusal happens in `/api/ebs-ops/middleware-run` and `/api/db-ops/run` before the command is ever queued for the agent, so it holds regardless of what the browser sends. Read-only ops are deliberately unaffected — status checks, ETCC runs, and every diagnostic query pass straight through, because seeing what the environment is doing mid-patch is exactly when you need it most. The dashboard shows a banner naming the current ADOP phase, and the gate lifts automatically the moment the detector observes the cycle has ended.

The rolling bounce is covered too, and refuses before its progress stream opens rather than failing halfway through — walking managed servers down one by one against a moving patch edition is the exact shape of the accident this prevents.

Every path decides the same way: each op carries a `destructive` flag on its catalog entry, and the gate reads that flag. It is not a list of op names kept somewhere else — a list drifts from the ops it names, and this one did.

It's a speed bump, not a locked door — and on the database side that matters more than it might look. Killing a session is exactly the tool you need when a session is blocking a hung ADOP worker, so refusing it outright would push you to sqlplus at the worst possible moment. An operator who genuinely needs a destructive op mid-cycle can re-send the request with the active ADOP session ID as `adop_session_id`. Requiring the session ID is the point: you can't clear the gate from muscle memory, you have to go and look at the patch cycle you're about to interfere with.

This gate exists specifically because "just restart the service, it'll be fine" is exactly the instinct that breaks an in-progress EBS patch. Its job is to interrupt that reflex and make you prove you know a patch cycle is running — not to take the decision away from you.

When a phase goes wrong, the guided execution flow is not the only path. ADOP Phase Status and ADOP Cutover Rollback remain valid DBA reference documentation for troubleshooting a stuck phase — they're for when something needs manual recovery outside the guided flow, at the sqlplus and `adop` command line.

See Connectivity & Agent Protocol for how these commands actually reach your servers, or Architecture Overview for how this fits into the rest of the system.