USE 597 - Support new parallel enrichments block in StepFunction - #344
Merged
Conversation
Why these changes are being introduced: The requirement going into this work was the ability to orchestrate the harvesting of fulltext for DSpace theses. A new harvester has been built and deployed already, and the general pattern *could* have been quite similar to embeddings, just daisy-chained after embeddings work in the StepFunction. However, this provided an opportunity to make some updates and improvements in the StepFunction. Previously, we had no way to skip embeddings for a given ETL run. With the addition of fulltext harvesting, which naively would have landed after the embeddings block in the StepFunction, this ability to skip particular stages would have been increasingly difficult to manage. Additionally, from a performance POV, it was not ideal to have the embeddings and fulltext harvesting work running sequentially when there is no reason they could not run in parallel. In summary, the need to support fulltext harvesting as new functionality in the StepFunction provided a good time to make some structural updates. How this addresses that need: The changes in the StepFunction are pretty significant, but often that requires only small alignments in the pipeline lambda. These changes are partially alignment with the StepFunction and truly new handlers for the dspace fulltext harvesting + indexing. - New handlers are added for new states in the TIMDEX StepFunction - prepare an "enrichments" object that provides a way to skip specific enrichments - prepare CLI commands for DSpace fulltext harvester and TIM indexing of fulltexts - manage the results of the parallel state in the StepFunction, resulting in a final success true/false - Continued refinement of next-step = (exit-ok, exit-error, end) - branches in the Parallel block in the StepFunction now return "end" indicating the branch is done, but this does not mean the StepFunction itself is done - Lastly, scaffold a final ETL run metrics handler - currently just logging the results, but this is a great place to publish to AWS metrics if desired Side effects of this change: * YES - Capable of handling new StepFunction architecture outlined in USE-560 - Logging of ETL run metrics Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/USE-597 * https://mitlibraries.atlassian.net/browse/USE-560
There was a problem hiding this comment.
Pull request overview
This PR updates the pipeline input-formatting Lambda to align with a new StepFunction architecture that runs enrichments (embeddings + DSpace fulltext harvesting/loading) in parallel, while also adding a scaffolded “finalize” step that reports ETL run metrics.
Changes:
- Introduces an
enrichmententry step that prepares/normalizes anenrichmentspayload for a StepFunctionsParallelblock and routes per-branch enrichment steps. - Adds fulltext harvesting/loading command preparation and a finalize handler that attaches run metrics to the StepFunction output.
- Adds dependencies (duckdb, pandas) and expands test coverage for new enrichment/fulltext/metrics behavior.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
lambdas/format_input.py |
Adds enrichment routing, fulltexts handlers, and a finalize step that logs/attaches metrics. |
lambdas/helpers.py |
Adds get_run_metrics() for record/action/enrichment counts from the dataset metadata. |
lambdas/commands.py |
Adds command generators for fulltext harvest and fulltext load operations. |
lambdas/config.py |
Expands valid input steps for the updated StepFunction flow; adds valid fulltexts sources. |
pyproject.toml |
Adds duckdb and pandas dependencies and mypy overrides for missing stubs. |
uv.lock |
Updates the resolved dependency set to include new requirements. |
tests/test_format_input.py |
Updates expectations for new enrichment step and adds tests for fulltexts + finalize output. |
tests/test_helpers.py |
Adds unit tests for get_run_metrics() including missing-view behavior. |
tests/test_commands.py |
Adds unit tests for fulltext command generation helpers. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
ehanson8
approved these changes
Aug 25, 2026
ehanson8
left a comment
Contributor
There was a problem hiding this comment.
Looks good to me and works as expected, one question and an optional suggestion but otherwise approved!
jonavellecuerdo
approved these changes
Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose and background context
Warning
These changes must be made in lockstep with StepFunction changes outlined in PR for USE-560
Why these changes are being introduced:
The requirement going into this work was the ability to orchestrate the harvesting of fulltext for DSpace theses. A new harvester has been built and deployed already, and the general pattern could have been quite similar to embeddings, just daisy-chained after embeddings work in the StepFunction.
However, this provided an opportunity to make some updates and improvements in the StepFunction. Previously, we had no way to skip embeddings for a given ETL run. With the addition of fulltext harvesting, which naively would have landed after the embeddings block in the StepFunction, this ability to skip particular stages would have been increasingly difficult to manage.
Additionally, from a performance POV, it was not ideal to have the embeddings and fulltext harvesting work running sequentially when there is no reason they could not run in parallel.
In summary, the need to support fulltext harvesting as new functionality in the StepFunction provided a good time to make some structural updates.
How this addresses that need:
The changes in the StepFunction are pretty significant, but often that requires only small alignments in the pipeline lambda. These changes are partially alignment with the StepFunction and truly new handlers for the dspace fulltext harvesting + indexing.
New handlers are added for new states in the TIMDEX StepFunction
Continued refinement of
next-step = (exit-ok, exit-error, end)Lastly, scaffold a final ETL run metrics handler
How can a reviewer manually see the effects of these changes?
1- Set Dev1
TimdexMangersAWS credentials2- Build SAM image for pipeline lambda:
And confirm that an env vars file is present at
tests/sam/env.json:{ "TimdexPipelineLambda": { "TIMDEX_ALMA_EXPORT_BUCKET_ID":"not-needed", "TIMDEX_S3_EXTRACT_BUCKET_ID":"timdex-extract-dev-222053980223" } }Note
the following assume that jq is installed for JSON parsing in the terminal
3- Confirm that new
enrichmentssection is propagated regardless ofnext-step. Here we make a call withnext-step = transform, but the enrichments block persists:{ "next-step": "load", "run-date": "2026-08-18", "run-type": "daily", "run-id": "6156c4dc-8559-4ad9-8c43-e5fba525cd01", "source": "dspace", "verbose": true, "transform": { "files-to-transform": [ { "transform-command": [ "--input-file=s3://timdex-extract-dev-222053980223/dspace/dspace-2026-08-18-daily-extracted-records-to-index.xml", "--output-location=s3://timdex-extract-dev-222053980223/dataset", "--source=dspace", "--run-id=6156c4dc-8559-4ad9-8c43-e5fba525cd01", "--run-timestamp=2026-08-25T13:53:09.567016+00:00" ] } ] }, "enrichments": { //<--- Note presence is maintained "message": "hello world!", "skip": false } }4- Confirm that a payload without an
"enrichments"block is created by lambda handler that begins enrichments parallel work, and thatnext-step = finalize:{ "next-step": "finalize", //<--- Next step is "finalize" "run-date": "2026-08-18", "run-type": "daily", "run-id": "618c6550-55d2-4c40-affd-07e4812df2d6", "source": "dspace", "verbose": true, "enrichments": { //<--- Added by lambda "skip": false, "embeddings": { "skip": false }, "fulltexts": { "skip": false } } }And, confirm that skip overrides are preserved:
{ "next-step": "finalize", "run-date": "2026-08-18", "run-type": "daily", "run-id": "33d99315-f1d3-41ee-9741-ef6ff16cb4b5", "source": "dspace", "verbose": true, "enrichments": { "skip": true, //<--- override persisted "embeddings": { "skip": false }, "fulltexts": { "skip": false } } }5- Confirm that
"finalize"handler in pipeline lambad retrieves run metrics. Here, we'll use a run fromdigitalcollectionsto demonstrate any run should work, no special treatment is needed.Logging output:
{ "next-step": "end", "run-date": "2026-08-13", "run-type": "full", "run-id": "496a7d87-9027-4351-9673-116a1492eef7", "source": "digitalcollections", "verbose": true, "metrics": { //<--- metrics are included in lambda response as well "records": { "count": 81762, "actions": { "index": 81762 } }, "embeddings": { "count": 81762 }, "fulltexts": { "count": 0 } } }Includes new or updated dependencies?
YES
Changes expectations for external applications?
YES
What are the relevant tickets?
Code review