Skip to content
Connect > Gateway

Gateway Routing

The Gateway reaches its Centers through routes defined in a routes file, which it monitors and reloads without a restart. This page covers the file format, its validation, the reload behavior, and the console commands that manage routes on a running Gateway.

Overview

Each route names a target Center and its address. The Gateway reads the routes file at startup and whenever it changes on disk, and it connects to every route it holds. A subscription is sent to every route, and a query to every route whose Center holds all the tables the query names. The results are merged, so the routes collectively define the data the Gateway exposes. Route targets are Centers.

File location

Set by ami.gateway.routes.file, which defaults to data/gateway.routes.

If the file does not exist when the Gateway starts, it is created containing a header comment and one example route to the local Center:

1
2
3
# AmiGateway routes
# One route per line: id;host:port;certificateFile
local;localhost:3270;keys/3forge.pub

Format

One route per line. Blank lines are ignored, as are lines beginning with #. Each route is 3 fields separated by semicolons:

id;host:port;certificateFile
Field Required Description
id Yes Identifier for the route. Must not be empty, and must be unique within the file
host:port Yes Address of the target Center. The port must be between 1 and 65535
certificateFile Yes, may be empty Certificate for connecting to the target. The path must be inside the installation root. Keeping it in the Gateway component's own directory is a convention, not a requirement

All 3 fields must be present. A line with a number of fields other than 3 is rejected with Expecting 3 parts (id;host:port;certificateFile) not <n>.

A certificate path outside the installation root is refused:

Ignoring changes to <file> due to parsing error: Access denied by ami_<name>:
<path> not in Permitted dirs (<installation root>)

Copy the target Center's public key somewhere under the installation root, for example the Gateway's own keys/, and reference it from there.

A failed addRoute leaves the routes file unusable

addRoute is not atomic. A call that returns an error still writes its line to the routes file, and a later call may report the earlier call's error text rather than describing its own input. The file is then refused on every reload, the existing routes stop serving, and queries return GATEWAY: Route no longer available.

After any failed addRoute, open the routes file and remove the bad line by hand, then confirm the routes reconnect. Do not assume a rejected call changed nothing.

This does not apply to editing the file directly: a malformed hand-edit is refused on re-read and the previously loaded routes keep running.

The certificate field may be left empty when no certificate is supplied, but the trailing semicolon is still required. An empty certificate field falls back to the instance's configured Center public key:

local;localhost:3270;

2 routes sharing an id are rejected with Duplicate gateway route id: <id>, so an accidental duplicate is caught rather than silently overriding.

Inspect the routes from a client

A client connected to the JDBC listener can list the routes with SHOW GATEWAY. The Gateway answers this itself rather than forwarding it to a route:

1
2
3
LineNumber | ID     | Host      | Port | CertFile             | Connected
0          | local  | localhost | 4270 |                      | true
1          | remote | localhost | 3271 | keys/remote.pub      | false

Connected reports whether the Gateway currently holds a connection to that route's Center, so this is the quickest way to tell a misconfigured route from an unreachable one without admin console access.

Route ids are visible to clients

A route id is not only an internal label. On a metadata statement the Gateway adds a first column named GatewayCenterId, holding the id of the route each row came from, so a client sees the ids chosen in the routes file:

GatewayCenterId | TableName    | Broadcast | ...
local           | __ANNOTATION | true      | ...

The column is added to SHOW and DESCRIBE TABLE results, for example DESCRIBE TABLE Trades. DESCRIBE alone is a syntax error. A plain SELECT does not carry it, because rows from the routes that answer are combined into one result set. Choose route ids that mean something to the people querying through the Gateway, rather than treating them as internal names.

Reload behavior

The Gateway checks the file on the interval set by ami.gateway.check.config.file.changes.period.ms, 2 seconds by default, and re-reads it when it has changed. Reloading is selective: each route is compared against the version already running, and only the differences are acted on. Unchanged routes keep serving, changed and removed routes are shut down, and new routes are started.

A malformed edit does not take the Gateway down. The parse error is logged, e.g: Ignoring changes to <file> due to parsing error: Error at line 3 ... Expecting 3 parts, and the previously loaded routes keep running, so the running configuration is never replaced by a broken one. Check the log after editing to confirm the change was accepted, because a rejected edit leaves the Gateway serving the old configuration with no other outward sign.

Removing a route on a running Gateway

On the build tested, removing a route with removeRoute left the remaining routes failing with GATEWAY: Route no longer available until the Gateway was reloaded, even though the routes file and showRoutes looked correct. Until this is confirmed fixed, reload the Gateway component after removing a route with ami.reloadComponent("<name>").

Use reloadComponent, not shutdownComponent, startupComponent or restartComponent. Those 3 do not work on a Gateway, see Stopping and starting a Gateway.

Managing routes from the console

The Gateway exposes console commands to inspect and change routes on a running instance.

Connect to the instance's admin console over SSH. The console port is printed in the startup log and defaults to 3285; sign in as an administrator:

ssh -p 3285 <admin-user>@<host>

At the prompt, invoke a command as a method on the Gateway component, named ami_<component-name> after the name in data/ami.components (a Gateway named gateway is ami_gateway):

1
2
3
ami_gateway.showRoutes()
ami_gateway.addRoute("secondary", "center-02.example.com:3270", "keys/3forge.pub")
ami_gateway.removeRoute("secondary")
Command Parameters Effect
showRoutes None Show all configured routes with their id, host, port, certificate file, and connection status
showRouteSubscriptions None Show each route's upstream subscriptions with type, row count, filters, and columns
showClientSubscriptions None Show each Gateway client subscription with type, in-focus row count, filters, and columns
showClients None Show all connected Gateway clients with their id, host, and subscription types
addRoute name, hostport, pubkeyfile Add a route to the routes file and connect it immediately
removeRoute name Remove a route from the routes file and disconnect it immediately

addRoute and removeRoute change live connections

addRoute and removeRoute write the routes file and change live connections immediately. Adding a route connects it at once. Removing a route disconnects it at once, but on the build tested it also leaves the surviving routes unusable until the Gateway is reloaded (see Removing a route on a running Gateway above): reload the component after a removeRoute.

Stopping and starting a Gateway

Use ami.reloadComponent("<name>") to apply configuration changes to a running Gateway. It re-reads the component's property files and restores its listeners.

Do not shut down or restart a Gateway component

ami.shutdownComponent(), ami.startupComponent() and ami.restartComponent() do not work on a Gateway, although they work on every other component type.

shutdownComponent reports Component shutdown: <name> and does stop the listeners, so the Gateway genuinely stops serving. It continues to report RUNNING in ami.showComponents(), and because of that startupComponent then refuses with Component is already running: <name>. restartComponent performs a shutdown followed by a start, so it fails the same way and leaves the Gateway stopped.

The state is recoverable without restarting AmiCore. ami.reloadComponent("<name>") brings the listeners back, and removing and re-adding the component also works.

The risk is that ami.showComponents() reports a stopped Gateway as RUNNING, so an operator watching component status does not see that clients have lost the Gateway.

Distribution model

A query is sent to every route whose Center holds all the tables in its FROM clause, and the responses are merged: plain results are combined, and aggregate (GROUP BY) results are re-aggregated across those routes. A route without one of the tables is skipped. If no route holds them all, the query fails with GATEWAY: Table not found: <table>, or GATEWAY: Set of tables not found: <table> + <table> for several. See the distribution model on the overview page.

What this does not support

  • Route targets are Centers only, not other component types.
  • A query cannot name the route it runs on. The routes are chosen from the tables it names.