Links to other boxes

A link lets one box call a service that runs in another of your boxes, under the name its callers already use: how to declare one, its rules, and what a connection gets in each state of the other box.

A link points a name in one box (B) at a port in another of your boxes (A), so B can call a service that runs in A under the name its callers already use. Declare it in B's services at start, or add it to B while it runs:

sandbox_start { "name": "web on the refund billing", "goal": "Run the web front end against the refund rework in box A; done when a refund placed in the browser is recorded by that billing", "services": [{ "name": "billing.acme.internal", "port": 8080, "fromBox": "<box A>", "fromPort": 8081 }] }
sandbox_wire  { "id": "<box B>", "service": "billing.acme.internal", "port": 8080, "fromBox": "<box A>", "fromPort": 8081 }
  • In B, name:port then reaches the process listening on fromPort in A, from B's own programs and from its containers. fromPort defaults to the targetPort of A's service with the same name, otherwise to port. In A, boxd opens the connection to 127.0.0.1:<fromPort>, so the process there must listen on 0.0.0.0 or 127.0.0.1, or be a container that publishes that port.

  • Rules: A must be another box of the same account and must not have stopped (410 … link to a running box); the name must be a host name, not an address or range; a link has no web or targetPort; a box cannot link to itself; fromPort cannot be 80 or 9095; and the name cannot also be a service of B (… is already a service in this box; a link needs a name of its own).

  • A link wins over an environment address with the same host:port: B reaches A instead of your network, and the address leaves B's environment.reachable.

  • sandbox_wire with fromBox returns { "links": [...] }. Passing the same service and port again with another fromBox or fromPort re-points the link; the next connection goes to the new target. A link is kept with the box: it appears in sandbox_status.services with fromBox and fromPort, and survives a boxd restart.

  • Added to a running box, a link takes over an environment address with the same host:port at once: new connections go to A, while connections already open keep their old route until they close. Checked on a box: before the link the name reached the connector; right after sandbox_wire … fromBox the next request reached A. A service or version added later takes an environment address over the same way on boxes with the take-over feature, and leaves it on the connector on older boxes (Taking over a link or an environment address).

  • What a connection from B gets depends on A's state:

    • frozen: A is thawed on connect, which needs credits on the account; if A is not awake within about 20 seconds, the connection fails with box … is still waking up from frozen; retry in a moment.
    • taken over by a person: works.
    • still starting: 409 link …: box … is still starting; retry once it is ready.
    • stopped or interrupted: 410 link …: box … is terminated (…); start a new box and re-point the link with sandbox_wire.
    • running an image from before links shipped: 409 … runs an older image … that cannot serve links; start a new box for it and re-point the link with sandbox_wire.
    • nothing listening on fromPort: 502 link …: nothing listens on port … in box ….

    The program in B sees its connection reset. The reason is in B's /work/.sbx/logs/private-endpoints.log and in sandbox_status.links[].lastError.

  • While B has connections open to A, A counts as busy: it is neither frozen nor stopped for being idle (A's health shows them as servedLinks). When B freezes or stops, ParallelSandbox closes its connections to A within about a minute, and A then freezes on its own idle time.

  • B's sandbox_status.links[] lists each link with fromStatus (A's state), active, opened, failed and lastError. A's sandbox_status.linkedFrom[] lists the boxes linked to it (boxId, boxName, status, name, port, fromPort). sandbox_stop on A returns the same linkedFrom with a note: those links fail until you re-point them with sandbox_wire.

  • Traffic goes through ParallelSandbox's control plane, not straight between the machines, and each direction counts as outbound traffic (box_egress) of the box that sends it: B's requests are B's, A's replies are A's.

  • Boxes started before links shipped cannot be linked to (409 runs an older image), and adding a link to a running box needs a box started after links shipped (409 … cannot add a link while it runs; declare the link at sandbox_start on a new box).

  • To change where a link goes, wire it again with fromBox or fromPort. To replace it with your own process or a published version when A is about to go away, wire the same name and port with port (and targetPort) or version: on boxes with the take-over feature that takes the link over in place and B keeps its URLs (Taking over a link or an environment address); on older boxes it fails with 409, and a new B, with new URLs, is the way. A mode switch on a link always fails with 409. Declaring the version in B from the start is simpler still: see Team setup.


Every tool and topic is listed in the tool reference.