Skip to content

Commit e85742e

Browse files
authored
Merge pull request #360 from alexhsamuel/fix/run-metadata
clean up run metadata
2 parents 6079648 + 52056ff commit e85742e

22 files changed

+134
-41
lines changed

.github/workflows/makefile.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ jobs:
1717
- name: Install Litestream
1818
run: wget --quiet https://github.com/benbjohnson/litestream/releases/download/v0.3.13/litestream-v0.3.13-linux-amd64.deb && sudo dpkg -i litestream-v0.3.13-linux-amd64.deb
1919

20+
- uses: actions/setup-python@v5
21+
with:
22+
python-version: '3.10'
23+
2024
- name: Upgrade pip
2125
run: pip3 install --upgrade pip 'setuptools>=61'
2226

python/apsis/actions/test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,36 @@ def from_jso(cls, jso):
111111

112112

113113

114+
class CheckLabelAction(BaseAction):
115+
"""
116+
Action that raises an exception if a run doesn't have a certain label.
117+
"""
118+
119+
def __init__(self, label, *, condition=None):
120+
super().__init__(condition=condition)
121+
self.__label = str(label)
122+
123+
124+
@classmethod
125+
def from_jso(cls, jso):
126+
with check_schema(jso) as pop:
127+
label = pop("label", str, None)
128+
condition = pop("if", Condition.from_jso, None)
129+
return cls(label, condition=condition)
130+
131+
132+
def to_jso(self):
133+
jso = super().to_jso()
134+
jso["label"] = self.__label
135+
return jso
136+
137+
138+
def __call__(self, apsis, run):
139+
if self.condition is not None and not self.condition(run):
140+
return
141+
labels = run.meta.get("job", {}).get("labels", [])
142+
if self.__label not in labels:
143+
raise RuntimeError(f"run missing label: {self.__label}")
144+
145+
146+

python/apsis/apsis.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,9 @@ def __prepare_run(self, run):
276276
return False
277277

278278
# Attach job labels to the run.
279-
if run.meta.get("labels") is None:
280-
run.meta["labels"] = job.meta.get("labels", [])
279+
run.meta["job"] = {
280+
"labels": job.meta.get("labels", []),
281+
}
281282

282283
return True
283284

@@ -365,19 +366,20 @@ def _run_exc(self, run, *, message=None):
365366

366367

367368
# FIXME: persist is a hack.
368-
def _update_metadata(self, run, meta, *, persist=True):
369+
def _update_metadata(self, run, meta):
369370
"""
370371
Updates run metadata, without transitioning.
371372
"""
372373
assert run.state in {State.starting, State.running}
373374

374-
run._update(meta=meta)
375-
# Persist the new state.
376-
if persist:
377-
self.run_store.update(run, now())
375+
if meta is None or len(meta) == 0:
376+
return
378377

378+
run.meta.update(meta)
379+
# Persist the new state.
380+
self.run_store.update(run, now())
379381
# Publish to run update subscribers.
380-
self.run_update_publisher.publish(run.run_id, {"meta": meta})
382+
self.run_update_publisher.publish(run.run_id, {"meta": run.meta})
381383

382384

383385
def _update_output_data(self, run, outputs, persist):
@@ -410,6 +412,10 @@ def _update_output_data(self, run, outputs, persist):
410412
def _transition(self, run, state, *, meta={}, **kw_args):
411413
"""
412414
Transitions `run` to `state`, updating it with `kw_args`.
415+
416+
:param meta:
417+
Metadata updates. Sets or replaces run metadata keys from this
418+
mapping.
413419
"""
414420
time = now()
415421
run_id = run.run_id
@@ -419,10 +425,6 @@ def _transition(self, run, state, *, meta={}, **kw_args):
419425
self.__db.run_log_db.flush(run.run_id)
420426
run.expected = False
421427

422-
# Update metadata. Don't persist; will persist with the run.
423-
# FIXME: Separate out metadata from Run and clean this up.
424-
if meta:
425-
self._update_metadata(run, meta, persist=False)
426428
# Transition the run object.
427429
run._transition(time, state, meta=meta, **kw_args)
428430
# Persist the new state.
@@ -431,6 +433,8 @@ def _transition(self, run, state, *, meta={}, **kw_args):
431433
# Publish to run update subscribers.
432434
if run_id in self.run_update_publisher:
433435
msg = {"run": run_to_summary_jso(run)}
436+
if len(meta) > 0:
437+
msg["meta"] = run.meta
434438
self.run_update_publisher.publish(run_id, msg)
435439
# Publish to summary subscribers.
436440
self.summary_publisher.publish(messages.make_run_transition(run))
@@ -797,7 +801,7 @@ async def _process_updates(apsis, run, updates):
797801
apsis._transition(
798802
run, State.running,
799803
run_state =running.run_state,
800-
meta =running.meta,
804+
meta ={"program": running.meta},
801805
times =running.times,
802806
)
803807

@@ -806,7 +810,7 @@ async def _process_updates(apsis, run, updates):
806810
apsis._update_output_data(run, error.outputs, persist=True)
807811
apsis._transition(
808812
run, State.error,
809-
meta =error.meta,
813+
meta ={"program": error.meta},
810814
times =error.times,
811815
)
812816
return
@@ -823,7 +827,7 @@ async def _process_updates(apsis, run, updates):
823827
if update.outputs is not None:
824828
apsis._update_output_data(run, update.outputs, False)
825829
if update.meta is not None:
826-
apsis._update_metadata(run, update.meta)
830+
apsis._update_metadata(run, {"program": update.meta})
827831

828832
case ProgramSuccess() as success:
829833
apsis.run_log.record(run, "success")
@@ -834,7 +838,7 @@ async def _process_updates(apsis, run, updates):
834838
)
835839
apsis._transition(
836840
run, State.success,
837-
meta =success.meta,
841+
meta ={"program": success.meta},
838842
times =success.times,
839843
)
840844

@@ -848,7 +852,7 @@ async def _process_updates(apsis, run, updates):
848852
)
849853
apsis._transition(
850854
run, State.failure,
851-
meta =failure.meta,
855+
meta ={"program": failure.meta},
852856
times =failure.times,
853857
)
854858

@@ -861,7 +865,7 @@ async def _process_updates(apsis, run, updates):
861865
)
862866
apsis._transition(
863867
run, State.error,
864-
meta =error.meta,
868+
meta ={"program": error.meta},
865869
times =error.times,
866870
)
867871

python/apsis/lib/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def run_to_summary_jso(run):
117117
"run_id" : run.run_id,
118118
"state" : run.state.name,
119119
"times" : { n: time_to_jso(t) for n, t in run.times.items() },
120-
"labels" : run.meta.get("labels", []),
120+
"labels" : run.meta.get("job", {}).get("labels", []),
121121
}
122122
if run.expected:
123123
jso["expected"] = run.expected

python/apsis/runs.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,16 +201,14 @@ def __str__(self):
201201
return f"{self.run_id} {self.state.name} {self.inst}"
202202

203203

204-
def _update(self, *, meta=None):
205-
if meta is not None:
206-
self.meta = meta
207-
208-
209204
def _transition(self, timestamp, state, *, meta={}, times={},
210205
message=None, run_state=None, force=False):
211206
"""
212207
:param force:
213208
Transition outside of the state model.
209+
:param meta:
210+
Metadata updates. Sets or replaces run metadata keys from this
211+
mapping.
214212
"""
215213
# Check that this is a valid transition.
216214
if not force and self.state not in TRANSITIONS[state]:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel=stylesheet href=/static/css/roboto.css><link rel=stylesheet href=/static/css/roboto-condensed.css><link rel=stylesheet href=/static/css/roboto-mono.css><title>apsis</title><link href=/static/css/app.2c00a3a669051c996f8e52bf4cc3abed.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.2ae2e69a05c33dfc65f8.js></script><script type=text/javascript src=/static/js/vendor.c925f914b965eeaf0032.js></script><script type=text/javascript src=/static/js/app.1759c586f7305af1844d.js></script></body></html>
1+
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel=stylesheet href=/static/css/roboto.css><link rel=stylesheet href=/static/css/roboto-condensed.css><link rel=stylesheet href=/static/css/roboto-mono.css><title>apsis</title><link href=/static/css/app.74e09c3bce8167f746a4f0af24143daf.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.2ae2e69a05c33dfc65f8.js></script><script type=text/javascript src=/static/js/vendor.c925f914b965eeaf0032.js></script><script type=text/javascript src=/static/js/app.7a05013375372941a20d.js></script></body></html>

python/apsis/service/vue/static/css/app.2c00a3a669051c996f8e52bf4cc3abed.css.map

Lines changed: 0 additions & 1 deletion
This file was deleted.

python/apsis/service/vue/static/css/app.2c00a3a669051c996f8e52bf4cc3abed.css renamed to python/apsis/service/vue/static/css/app.74e09c3bce8167f746a4f0af24143daf.css

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/apsis/service/vue/static/css/app.74e09c3bce8167f746a4f0af24143daf.css.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/apsis/service/vue/static/js/app.1759c586f7305af1844d.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)