Decoupled AI services reading a TMS replica and returning suggestions on a queue so the live dispatch grid is not locked
Applied AI Systems Architecture

Decoupled AI Microservice Architecture

Preventing database locking on legacy TMS. Forecasts, document extract, rate suggestions, and dispatch suggestions stay off the live dispatch database. If the copy they read is stale, they abort. If they are slow, the board keeps the rule it already has.

Key takeaways
  • No AI login on the primary. The model tier reads a replica or an outbound event, never the live dispatch grid.
  • The replica has a written freshness ceiling. Past it, the service aborts and writes no suggestion.
  • Each service gets one write: an insert on its own queue or staging table.
  • The board waits zero seconds on the model. A timeout means the current TMS rule stands.
  • Prove it with before-and-after wait stats and dispatcher save times from the carrier's own weeks.
4services, each with one allowed insert
60 secillustrative lag ceiling for advice shown on the live board
30 secillustrative statement timeout on the replica
0 sectime the board waits on the model

Who this page is for

Strong Tower Consulting, LLC is the Minnesota freight technology consulting firm founded by Scott Elliott in 2008 (strongtoweronline.com). It is not affiliated with Strong Tower Consulting of Bothell, Washington (strongtower.consulting or strongtower.ai).

The audience is a carrier whose dispatchers already live in a legacy TMS on SQL Server or Oracle. The grid is the system of record for orders, stops, and assignments. An AI process that logs into that same database to "just read the board" is a second user of the only screen the morning depends on. This page splits the work: events and a replica go out, suggestions come back on a queue, and a person accepts them through the save path the TMS already has.

Why an AI process must not query the live dispatch grid

The live grid is a short, hot set of rows. Dispatchers open loads, change status, assign drivers, and save appointments in the same minute. Those saves need brief locks and a quiet buffer pool. An AI job is the opposite shape. It scans history, joins stops to positions, and holds a plan for seconds or minutes. Put that scan on the primary and it competes for CPU, memory, and locks with the people who are trying to move trucks. The job does not have to be malicious to cause a freeze. It only has to be large, and it only has to run while the board is busy.

A synchronous call from the board refresh to a model is the same mistake in application clothing. The screen waits. The database session behind the screen stays open. If the model is slow, the dispatcher stares at a spinner and the connection pool fills with sessions that are not dispatching. The architecture rule is blunt.

The architecture rule

No AI login on the primary. No select from the model tier against the live order and stop tables. No trigger on those tables that calls out to a service. Advice is computed elsewhere and offered as a row the board may show if it is already there.

Locking symptoms dispatchers feel

On SQL Server, dispatchers feel the board stop painting, a status change that spins, or a save that returns a timeout. A DBA looking at the same minute often finds lock waits: the dispatch session waiting on an exclusive lock while another session holds shared locks across the dispatch tables, or lock escalation that turned a few row locks into a partition or table lock. A reporting login and an AI login look the same from the dispatch chair. Read committed snapshots can reduce reader-versus-writer blocking, and they do not make it safe for an AI job to update live rows or to run an unbounded scan that drives the buffer pool out from under the board. The symptom to respect is the chair, not a theory that "selects never hurt."

On Oracle, a plain query usually does not block a writer, because readers reconstruct rows from undo. Dispatchers can still feel the host stall: the form hangs, saves wait, and the board query that used to be instant becomes slow because CPU and I/O are saturated. When an "AI helper" does take a lock, it shows up as a row-lock enqueue, the wait dispatchers experience as a save that will not finish. Select for update, an advisory job that "reserves" a load, and a batch update of ETA columns are locks, even if the program calls them enrichment. The rule does not change by vendor. If the session can see the live dispatch schema, it is in the wrong place. Wait names are how you prove the cause later. They are not a reason to allow the session.

Read-replica or snapshot contract

The AI tier reads a replica or a snapshot, and the contract is written down before the first model is deployed. A SQL Server readable secondary, an Oracle replica, or a scheduled extract all qualify if they have an as-of time the service can read. The service compares that as-of time to now. Illustrative ceilings, which the carrier replaces with its own: 60 seconds of lag for any suggestion that will be shown on the live board, and 15 minutes for a toll or cost input that a rate suggestion depends on. A nightly training extract may be hours old. It must say so in the file name and in the row, and it must not be wired to the board.

If the ceiling is missed, the service aborts. It does not score, and it does not enqueue a suggestion stamped as current. Silence is the safe output. A statement timeout, illustrative 30 seconds, kills a runaway read on the replica so a bad join cannot pile up there either. The login is select-only. There is no link from the replica job back to the primary "for one column that is missing." That link is how the live grid gets a surprise reader. Lag over the ceiling is also a page for the database owner. It is not a cue to point the connection string at the primary until the replica catches up.

Event bus out, recommendation queue back

Changes leave the TMS on a bus. The durable pattern is an outbox row written in the same transaction as the order or stop change, then a publisher that sends the outbox to the bus. The publisher is not a trigger that makes an HTTP call while the dispatcher is holding the save. Events worth sending are small: order created or changed, stop or appointment changed, assignment changed, status changed. The payload carries keys and the change, not a dump of every rate column on the order. Consumers that need history read the replica under the freshness contract. They do not poll the live grid to "catch what the bus missed." A gap in the bus is an operations incident. Filling the gap from the primary is forbidden.

Suggestions return on a queue the TMS integration already owns, or on a staging schema that is not the dispatch grid. Each message has a type, a suggestion id, an expiry, an idempotency key, and the input hash it was computed from. The board reads that queue the way it reads any other inbox: a short query by load id, no scan of history. Accepting a suggestion is a normal TMS save by a person, which takes the same brief lock a dispatcher save takes today. The model never performs that save. Forecasts, extracts, rate ideas, and dispatch ideas all die on the queue if nobody accepts them. That is the point.

Events out, suggestions back
TMS outboxRow written in the same transaction as the change
Event busKeys and the change, not a dump of rate columns
AI serviceReads the replica inside the freshness ceiling
Suggestion queueType, id, expiry, idempotency key, input hash
Person acceptsNormal TMS save. The model never performs it
The model tier never opens a session on the primary.

Service boundaries and the one write each is allowed

Four services cover the decisions this framework will support. They do not share a database login, and they do not write each other's tables. A forecast service estimates arrival or dwell. A document extract service reads images from an object store and proposes fields. A rate suggestion service proposes a linehaul that still has to clear the margin floor hard stop before anything is transmitted. A dispatch suggestion service proposes an assignment a person can accept. None of these is an autonomous actor on the grid.

The one write is an insert on that service's own queue or staging table. A second write, "while we are here," is how a suggestion becomes an unreviewed update to a live order. Billing may later accept a document extract through the billing screen. Pricing may later transmit a rate through the quote API. Dispatch may later assign a driver through the board. Those writes belong to the existing TMS workflows and to the people who run them. They are not extra privileges on the AI login.

Service boundaries. Each service gets one insert on its own staging or queue table. None of them update the live dispatch grid.
Service May read The one write allowed Not allowed
Forecast Replica of stops, appointments, and recent position events inside the freshness ceiling Insert a forecast row: band, as-of time, input hash Update live ETA columns or lock a load
Document extract Image store and document metadata. Not the dispatch grid. Not rate tables. Insert a staging extract: fields, confidence, document id Post an invoice or alter the order
Rate suggestion Replica of the rate history that service alone is granted, plus the cost file Insert a suggestion: proposed linehaul, model version, floor version Transmit a rate or write the customer rate on the order
Dispatch suggestion Replica of open loads and hours, inside the freshness ceiling Insert a suggestion a dispatcher can accept or ignore Update the live assignment or tender the load

Idempotency keys

Buses deliver twice. Retries are normal. Every suggestion is stored under a key built from the source event id, the service name, and the model version. A second delivery of the same event returns the stored suggestion and does not insert another. The input hash sits beside the key. If the event id is reused with a different payload, the service records a conflict and does not publish a second opinion under the original key. A person looking at the queue should never see two active forecasts for one stop from one model version.

A new model version is a new key, not an overwrite. The prior suggestion keeps its id and receives an expiry so the board stops showing it. Overwriting in place hides what the dispatcher actually saw. Acceptance has its own key, on the TMS side, covering suggestion id plus user id. A double-click, or a replay of the AI message, cannot create a second assignment. The AI service is not allowed to submit the acceptance. Its key authorizes a suggestion insert. It does not authorize a grid update. The same pattern protects a rate suggestion: the quote API's idempotency key, described on the floor page, is a different key from the suggestion key, and a retry of the model cannot mint a transmitted rate.

Timeout behavior

The board does not call the model and wait. On refresh it looks for a suggestion already on the queue, unexpired, whose input hash still matches the load. Illustrative timings the carrier can tighten: the board waits zero seconds on the model, a dispatch suggestion expires 15 minutes after it was written, and a forecast expires when the appointment or the stop set changes. If nothing qualifies, the screen is the TMS screen the carrier had last year. The current assignment rule, the current rating rule, and the current ETA field remain in force.

Illustrative timings, not a customer result

The carrier can tighten these.

board wait on model = 0 sec dispatch suggestion expiry = written + 15 min forecast expiry = appointment or stop set changes

A timeout is a missing suggestion, not a failed freight movement. Do not queue the load into an error status. Do not hold the driver. Do not block the rate confirmation on a model that has not answered. Operators can see "no suggestion" in a side panel if that is useful, and they can dispatch without opening the panel. If the replica is stale, the abort path above produces the same user-visible result as a timeout: no new advice, existing rule stands. Paging someone about lag is an infrastructure alert. It is not painted as a red banner that stops the board from saving.

On timeout or stale data

  • Show no new advice
  • Keep the current TMS rule in force
  • Page the database owner about lag

Avoid

  • Queueing the load into an error status
  • Holding the driver or the rate confirmation
  • Pointing the connection string at the primary

Security of the replica

A replica is a copy of operational data, and rate data is the sensitive part. Customer linehaul, pay, and accessorial amounts are granted only to the rate suggestion service, on the replica, through a view that lists those columns and no others. The forecast service is denied those tables. The document service is denied them. The dispatch suggestion service does not need the dollar columns to propose a driver, and it does not get them. A shared "analytics" login that can read every table is a second copy of the rate file with a friendly name. Do not create it.

No extra copies of rates leave that service. Training extracts for the rate model stay in its store, encrypted, with the same people who can already see rates in the TMS. They are not dropped on a file share, a notebook, or a vendor workspace "so the model can be improved." Other services do not mount that store. A vendor demo, if one happens, gets a de-identified sample the carrier built, or nothing. The replica password is not the primary password, and it is not reused across the four services. Column grants are reviewed when a table is added. A new column on the order table does not automatically become visible to every reader.

How a carrier proves the live board was not locked

Proof is a before and after, taken on the live instance, during the same kind of dispatch window. Pick two weeks that both include the morning peak, and write the dates down before cutover so nobody chooses the quiet week after the fact. The before is the baseline with no AI login on the primary. The after is the same measures with the services in production on the replica and the queue. The pass condition is structural first: there is still no AI principal on the primary, so no blocking chain can be headed by one. The pass condition is experiential second: dispatcher save time does not worsen past a tolerance the carrier set in advance.

Wait stats are the database half of that proof. On SQL Server, capture a delta of lock waits and the blocked-process report for the dispatch window, and confirm the sessions in any chain are dispatcher and TMS service accounts you already know. On Oracle, use session wait samples for the dispatch module over the same hours, and confirm row-lock enqueues are not new and are not tied to a new machine. Application logs supply save-time percentiles so the proof is not only a DBA graph. If save time jumps and the waits do not, look for a synchronous call the board was not supposed to make. The AI tier is still not allowed onto the primary as a debugging shortcut.

Before-and-after evidence that the live board was not locked by an AI process. Capture the baseline before cutover. Do not backfill it later. Figures are not supplied here because they must be the carrier's own.
Evidence Before After Pass
Principals on the primary List of logins that can connect to the live TMS database The same list No AI service login was added
SQL Server lock waits Delta of lock waits and any blocked-process report during the morning peak The same capture No chain names an AI session. Dispatcher save waits are inside the pre-set tolerance.
Oracle row-lock enqueues Wait samples for the dispatch module during the same hours The same capture No new enqueue source. Host CPU during that window is not explained by an AI query on the primary.
Dispatch save time p50 and p95 from the application log p50 and p95 for the matched window Not worse than the tolerance written down before cutover
Suggestion path Not in production Queue inserts only, from the replica-side services Accepts show up as ordinary TMS saves by a person, not as updates by the model

What this split does not decide

Decoupling keeps the board available. It does not make a forecast true, a rate legal, or an assignment wise. Dwell labels and facility clocks are specified in the detention risk guide. A dispatch suggestion still has to respect hours, appointments, and equipment, which is the subject of the constraint guide. A rate suggestion still stops at the floor. The replica contract is what lets those projects run without taking the morning grid down while they are wrong, and they will be wrong sometimes.

Cut over one service at a time.

  1. Forecast first. This is the usual order because a wrong band is visible and does not move money.
  2. Document extract next. Into staging only.
  3. Rate suggestions. Only after the floor check exists in the quote API.
  4. Dispatch suggestions last. Only as a panel a person can ignore.

If any step requires a login on the primary, stop. The legacy TMS stays the system of record. The microservices are advisors with a narrow pen and a clock that tells them to be quiet when their data is old.

Frequently asked questions

These answers are the cutover test. A design that needs a primary login, even a read-only one, for the model tier does not pass.

Wait stats and save times are collected on the carrier's own weeks. This page does not supply a sample result to copy into an audit.

Why must an AI process stay off the live dispatch database?

The live database is the dispatch grid. A long read or any write from an AI login competes with the saves dispatchers make all day. The AI tier reads a replica or an outbound event, and it returns advice on a queue. It does not open a session on the primary.

What do dispatchers feel when something locks the board?

The board stops refreshing, a status save spins, or the save times out. On SQL Server that often shows up as lock waits. On Oracle a writer shows up as a row-lock enqueue, and a heavy read shows up as a slow host even when a plain select does not block. Either symptom is a reason to keep AI off that database.

What happens when the replica is past its freshness ceiling?

The service aborts and writes no suggestion. A stale score presented as current is worse than silence. Training may use an older extract only when the extract is labeled with its as-of time and is not used to advise the live board.

What is the one write each AI service is allowed?

Each service may insert one kind of row on its own queue or staging table: a forecast, a document extract, a rate suggestion, or a dispatch suggestion. None of them update the live order, the live assignment, or a transmitted rate. A person accepts through the normal TMS save.

What does dispatch do if a suggestion times out?

Dispatch continues on the current TMS rule. The board does not wait on the model. A missing suggestion is not a failed load. The existing assignment screen, rating path, and ETA field keep working.

Talk to an architect

Add AI without locking the morning board.

Strong Tower Consulting provides independent systems architecture, feasibility audits, and engineering roadmaps for motor carriers and freight brokers. Contact our advisory team or call 763-244-1373 to discuss your operational data and evaluate practical implementation paths for your fleet.

Published October 23, 2026 by Strong Tower Consulting, LLC. Founded 2008 in Minnesota by Scott Elliott.