Create data orchestration pipelines over AWS Lambda functions from within python code using decorators
Project description
OrchWiPy
Create data orchestration pipelines over AWS Lambda functions from within python code using decorators.
- No need for separate definition file, you define the orchestration + lambda functions in the code
- Simpler data passing: only return changes to current state rather than the whole state
- Visualize flow graph
- Statically check state passing between steps
- Generate AWS cloudformation template automatically
- Run locally
- Handle lambda invocation payload size limit transparently
We developed OrchWiPy at ask-next.com
Example
from orchwipy import MicroFunctions, ConditionalReturns, ReturnUpdates
from orchwipy import build_cfn_template
# Our pipeline starts at function 'start'
pipe = MicroFunctions(beginner="start")
@pipe.fn()
# pipe.fn() will convert this to a lambda function when deployed
def start(*, choice: str | None, **kwargs):
# **kwargs is always needed
beans = None
if not choice:
choice = input("Tea or coffee? (t/c)")
if choice == 'c':
beans = int(input("How much beans "))
# if choice is 'c', then we go to 'coffee' else 'tea'
return ConditionalReturns(
choice,
# default choice is 'tea'
# "*" => passing no other arguments, required for first step
ReturnUpdates("tea", "*"),
# only include beans argument
c=ReturnUpdates("coffee", "*", beans=beans))
@pipe.fn(template_props=dict(Layers=[{"Ref": 'MorePythonPackagesLayer'}]))
# MorePythonPackagesLayer will become a CFN template parameter
def tea(**kwargs):
print("Have tea")
# can also return a dictionary, with $next as the next function name
return {"$next": "coffee", "beans": 5}
@pipe.fn()
def coffee(*, beans: int, **kwargs):
print(f"Put {beans} beans into the coffee machine")
# include all the arguments passed previously and add (update) the milk argument
return ReturnUpdates("drink", milk=True)
@pipe.fn(terminates=True)
# terminates => specify that this may be the end of the pipe
def drink(*, milk: bool | None, **kwargs):
if milk:
print("Add some milk if its bitter")
print("Drink!")
return {}
# boilerplate: pass execution to pipe when running in AWS lambda
def lambda_handler(event, context):
pipe.lambda_handler(event, context)
if __name__ == "__main__":
pipe.check_graph("start")
# local run
pipe.run(choice=None)
# check execution pipeline and generate a graphviz graph for visualization
with open("example.dot", "w") as f:
pipe.save_dot(f, top_node="start")
# generate a aws cloudformation template for deployment
with open("example.template.yml", 'w') as f:
build_cfn_template(
output_template=f,
code_py_relative_to_template=__file__.split("/")[-1],
plant=pipe,
layers=[],
policies=[],
)
Visualization
It generates a graphviz dot diagram example.dot:
flowchart TD
start["start"] --> cond1@{ label: "choice == 'c' ?" }
tea["tea"] --> coffee["coffee"]
coffee --> drink["drink"]
cond1 -.-> coffee
cond1 --> tea
cond1@{ shape: rect}
style cond1 stroke:#FFD600
Static checking
This involves checking all the execution paths to ensure that all the required function arguments are passed through all possible invocations.
In the above example, if we replace this line in function tea:
return {"$next": "coffee", "beans": 5}
with
return {"$next": "coffee"}
then the coffee step will not receive the beans argument when execution flows through start -> tea -> coffee . Invoking pipe.check_graph(start_at="start") will throw us this warning:
:0: MissingArgument: {'beans'} : caller history ['start', 'tea'] -> coffee
More Examples
tests/sample.py is another example:
flowchart TD
welcome["welcome"] --> cond1@{ label: "choice = 't' ?" } & cond2@{ label: "choice = 'c' ?" } & cond3["choice = * ?"]
making_tea["making_tea"] --> boil_water["boil_water"]
making_coffee["making_coffee"] --> boil_water
boil_water --> cond4@{ label: "choice = 'coffee' ?" }
grind["grind"] --> pour_water["pour_water"]
dip["dip"] --> pour_water
pour_water --> drink["drink"]
cond1 --> making_tea
cond2 --> making_coffee
cond3 --> nochoice["nochoice"]
cond4 --> grind
cond4 -.-> dip
cond2@{ shape: rect}
cond4@{ shape: rect}
style cond1 stroke:#00C853
style cond2 stroke:#00C853
style cond3 stroke:#00C853
style cond4 stroke:#2962FF
Why
Building complex backend pipelines AFAIK requires creating pipeline definitions separate from the code itself. In my experience, this creates a lot of technical baggage. Futher, serverless backends (with AWS Lambda) gives us a lot of scalability but its hard to run locally. Also, Step Functions are great but without static checking, its very easy to get missing data errors while in production.
Orchwipy tries to solve all these issues by having your code as the single source of truth about your data pipeline. Deployment templates, static checking, ... everything simply derives from it.
At ask-next.com Orchwipy orchestrates our data pipeline with ~50 services
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file orchwipy-0.1.0.tar.gz.
File metadata
- Download URL: orchwipy-0.1.0.tar.gz
- Upload date:
- Size: 20.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4042152389c517b975a8025d7b4df9e001187d94f9407c4d836a828c0af4185
|
|
| MD5 |
3e77cbd548807bffe820af8febc562c7
|
|
| BLAKE2b-256 |
441fbcbdc1ab3d2f1f8b3fd080fb125850bd04e60307ea6da1921fa183b7fe3b
|
File details
Details for the file orchwipy-0.1.0-py3-none-any.whl.
File metadata
- Download URL: orchwipy-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f98bfe6499d667bdf1ec9a387cd60fd2031d1d2ebb90b40891de03355d3febf
|
|
| MD5 |
441783bdbdff0c0938b48512c7f47fb6
|
|
| BLAKE2b-256 |
72ba8f8791773c12196a9bab9c717a0cf2284d774617d01ab46583b5d1da2e6a
|