Skip to content

Commit

Permalink
adding post-abort start and active check endpoints (#200)
Browse files Browse the repository at this point in the history
Removing enable_commit in favor of single enable_control gate, then provide active status in healthz and state endpoints based on this, along with a start endpoint that re-enables control of the system. This will power the abort/start UI toggle functionality.
amitschang authored Nov 6, 2024

Verified

This commit was signed with the committer’s verified signature.
primeos Michael Weiss
1 parent f7d76a0 commit 67b1924
Showing 6 changed files with 38 additions and 21 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -45,7 +45,6 @@ for example:

```yaml
enable_react: true # run the experiment controllers
enable_commit: true # enable controllers to send commands to hardware
interval: 20 # how often in seconds to loop
hardware:
temp:
8 changes: 4 additions & 4 deletions docs/source/concepts.rst
Original file line number Diff line number Diff line change
@@ -101,10 +101,10 @@ following steps in succession:
These activities are coordinated in the
:py:class:`Evolver<evolver.device.Evolver>` class, via the
:py:meth:`loop_once<evolver.device.Evolver.loop_once>` method, and executed
continuously within the application. Configuration options `enable_control` and
`enable_commit` control whether the control (executing the `commit` method of
Controllers) and commit steps (executing the `commit` method of Effectors) are
executed, respectively.
continuously within the application. Configuration option `enable_control`
controls whether the control (executing the `control` method of Controllers) and
commit steps (executing the `commit` method of Effectors) are executed during
the loop.


.. _buffering:
20 changes: 13 additions & 7 deletions evolver/app/main.py
Original file line number Diff line number Diff line change
@@ -65,8 +65,7 @@ async def validation_error_handler(_, exc):
async def describe_evolver():
return {
"config": app.state.evolver.config_model,
"state": app.state.evolver.state,
"last_read": app.state.evolver.last_read,
**await get_state(),
}


@@ -75,6 +74,7 @@ async def get_state():
return {
"state": app.state.evolver.state,
"last_read": app.state.evolver.last_read,
"active": app.state.evolver.enable_control,
}


@@ -106,7 +106,7 @@ async def get_history(

@app.get("/healthz", operation_id="healthcheck")
async def healthz():
return {"message": f"Running '{__project__}' ver: '{__version__}'"}
return {"message": f"Running '{__project__}' ver: '{__version__}'", "active": app.state.evolver.enable_control}


async def evolver_async_loop():
@@ -144,21 +144,27 @@ async def calibrate(name: str, data: dict = None):
@app.post("/abort")
async def abort():
app.state.evolver.abort()
# Disable commit also in persistent config in case application needs to restart
# Disable control/commit also in persistent config in case application needs to restart
config = Evolver.Config.load(app_settings.CONFIG_FILE)
config.enable_control = False
config.enable_commit = False
config.save(app_settings.CONFIG_FILE)


@app.post("/start")
async def start():
config = Evolver.Config.load(app_settings.CONFIG_FILE)
config.enable_control = True
await update_evolver(config)


app.mount("/html", html_app)


def start():
def start_app():
import uvicorn

uvicorn.run(app, host=app_settings.HOST, port=app_settings.PORT, log_level="info")


if __name__ == "__main__":
start()
start_app()
21 changes: 17 additions & 4 deletions evolver/app/tests/test_app.py
Original file line number Diff line number Diff line change
@@ -37,11 +37,12 @@ def test_healthz(self, app_client):
assert response.status_code == 200
if __version__:
assert __version__ in response.json()["message"], response.json()
assert response.json()["active"]

def test_evolver_app_default_config_dump_endpoint(self, app_client):
response = app_client.get("/")
assert response.status_code == 200
assert sorted(response.json().keys()) == ["config", "last_read", "state"]
assert sorted(response.json().keys()) == ["active", "config", "last_read", "state"]

def test_EvolverConfigWithoutDefaults(self):
EvolverConfigWithoutDefaults.model_validate(Evolver.Config().model_dump())
@@ -208,12 +209,24 @@ def test_history(self, app_client, query_params):
assert response.json() == {"data": {}}

def test_abort_endpoint(self, app_client):
assert app.state.evolver.enable_commit
assert app.state.evolver.enable_control
response = app_client.post("/abort")
assert response.status_code == 200
assert not app.state.evolver.enable_commit
assert not app.state.evolver.enable_control
saved_config = Evolver.Config.load(app_settings.CONFIG_FILE)
assert not saved_config.enable_commit
assert not saved_config.enable_control
# healthz and state should report inactive state
for endpoint in ("/healthz", "/state"):
response = app_client.get(endpoint)
assert response.status_code == 200
assert not response.json()["active"]

def test_start_endpoint(self, app_client):
_ = app_client.post("/abort")
assert not app.state.evolver.enable_control
response = app_client.post("/start")
assert response.status_code == 200
assert app.state.evolver.enable_control


def test_app_load_file(app_client):
3 changes: 0 additions & 3 deletions evolver/device.py
Original file line number Diff line number Diff line change
@@ -24,7 +24,6 @@ class Config(BaseInterface.Config):
serial: ConfigDescriptor | Connection = ConfigDescriptor.model_validate(DEFAULT_SERIAL)
history: ConfigDescriptor | History = ConfigDescriptor.model_validate(DEFAULT_HISTORY)
enable_control: bool = True
enable_commit: bool = True
interval: int = settings.DEFAULT_LOOP_INTERVAL

def __init__(self, *args, **kwargs):
@@ -90,12 +89,10 @@ def loop_once(self):
# for any hardware awaiting calibration, call calibration update method here
if self.enable_control:
self.evaluate_controllers()
if self.enable_commit:
self.commit_proposals()

def abort(self):
self.enable_control = False
self.enable_commit = False
for device in self.effectors.values():
device.off()

6 changes: 4 additions & 2 deletions evolver/tests/test_device.py
Original file line number Diff line number Diff line change
@@ -156,7 +156,9 @@ def off(self):
self.aborted = True

demo_evolver.hardware["testeffector"] = AbortEffector()
demo_evolver.enable_commit = True
demo_evolver.enable_control = True
assert demo_evolver.enable_control
demo_evolver.abort()
assert not demo_evolver.enable_commit
assert not demo_evolver.enable_control
assert demo_evolver.hardware["testeffector"].aborted
assert not demo_evolver.enable_control

0 comments on commit 67b1924

Please sign in to comment.