Lease: the Control Lease (X-Lease-Id, 409, 423)¶
Control lease summary: take it with POST /api/lease (409 when someone else holds it), send
X-Lease-Idwith every request, renew before it expires, release when done. Everyone else gets 423 Locked for changes and forced reads meanwhile.
The control lease lets one client at a time change the station, typically a test station for the length of a test sequence, so that nobody else changes a setting in the middle of it.
While another client holds the lease, this client's changes (every POST, PUT and DELETE that changes something) and forced reads (resources.get_value, resources.get_values without max_age_ms) raise AccordionQ2ApiError with status 423. Reads with max_age_ms and subscriptions keep working; they get the values the holder's own reads keep up to date. Anyone may ask who holds it.
After acquire() the client sends the lease id (the X-Lease-Id header) with every request, so its own changes go through as if there were no lease.
Methods: Acquire, Renew and Release the Control Lease¶
| Method | Returns | Description |
|---|---|---|
get() |
LeaseDto |
Who holds the lease, if anyone. |
acquire(owner, ttl_ms=30000) |
LeaseDto |
Take the lease for ttl_ms (1 000 to 600 000 ms). Raises 409 while someone else holds it. |
renew(ttl_ms=None) |
LeaseDto |
Renew the lease this client holds, optionally with a new time to live. Raises 404 once it has ended, and RuntimeError when this client holds none. |
release() |
— | Release the lease this client holds; does nothing when it holds none. |
hold(owner, ttl_ms=30000) |
context manager yielding LeaseDto |
Acquire, renew in the background, and release when the block ends. |
held_lease_id |
str or None |
Property: the id of the lease this client holds. |
A lease not renewed within its time to live ends by itself, so a crashed test station doesn't lock the station.
Examples¶
Holding the Lease for a Sequence¶
with client.lease.hold("TAT station 3", ttl_ms=30000):
client.resources.set_value("0.4.ESH10000662.VSET1", "5")
voltage = client.resources.get_value("0.4.ESH10000662.VMON1")
hold renews the lease every third of ttl_ms on a background thread and releases it when the block ends, also on an exception. If the script dies, the lease ends within ttl_ms.
Who Holds It¶
lease = client.lease.get()
if lease.held:
print(f"Held by {lease.owner} for another {lease.expires_in_ms / 1000:.0f} s")
Acquiring and Releasing by Hand¶
from accordionq2 import AccordionQ2ApiError
try:
client.lease.acquire("TAT station 3", ttl_ms=60000)
except AccordionQ2ApiError as e:
if e.status_code == 409:
print("Someone else holds the lease:", e)
raise
try:
client.resources.set_value("0.4.ESH10000662.VSET1", "5")
client.lease.renew() # within ttl_ms, or the lease ends
finally:
client.lease.release()
Handling 423 in Another Client¶
try:
client.resources.set_value("0.4.ESH10000662.VSET1", "5")
except AccordionQ2ApiError as e:
if e.status_code == 423:
print("The station is held by another client:", e)
Pilot Is Not Bound by the Lease¶
The lease is enforced by the WebApi, which from 7.0 is the only way to the station, so every client is bound by it. On a 6.x station Accordion Pilot talks over the byte protocol, not the REST API, so it is not bound by the lease: it can change the station while someone holds it. Keep Pilot away from a 6.x station during a leased test sequence.
Model¶
LeaseDto¶
| Field | Type | Description |
|---|---|---|
held |
bool |
True while someone holds the lease |
owner |
str or None |
The owner name the holder gave |
expires_in_ms |
float |
Time left before the lease ends unless renewed |
lease_id |
str or None |
The lease id, on the LeaseDto that acquire() returns; None from get() |