Store each launch
Add a unique constraint on active rows for each learner and lab. It stops two tabs from launching the same lab at once.
Launch, or resume an active lab
Each launch counts toward your usage and limits. Before launching, look for an active row for the same learner and lab, and return it instead:Check ownership on every request
For status, terminal, and end requests, find the row for the current learner and lab. Use only thedeploymentId from that row:
End labs
When the learner ends a lab early, for example with an End lab button, calldestroy() and close the row:
not_found, conflict, or deployment_failed error from destroy() means the lab is already over. Close the row in that case too.
When lab.timeLimit is set, Cybr ends the lab automatically at launchedAt plus timeLimit minutes. Show a countdown to that time, and close the row when it passes or a status check returns failed.
Failed launches
Atimeout or network_error from launch() is ambiguous. The launch may have started a deployment before the connection failed, and the API has no idempotency key.
Do not launch again automatically. Ask the learner to wait a minute before trying again. A deployment that did start ends at its time limit.
The error guide covers the same rule for other writes.