Joseph Wibowo
12/04/2025, 7:42 AMUsage in deployment yaml:
entrypoint: src/core/pipeline/entrypoints.py:get_tenant_orchestrator("mock-tenant")
I am trying to create a generic orchestrator flow that can be reused but I don't want it to be reused across all flows, I want separation of this flow into specific categories so all deployments don't just go into the same flow. I have this entrypoint proposal but it seems wonky and hacky. Whats the prefect way to do this?Marvin
12/04/2025, 7:42 AMMarvin
12/04/2025, 7:46 AMentrypoint: src/core/pipeline/entrypoints.py:get_tenant_orchestrator("mock-tenant")
If you want separation so deployments don’t all land under the same flow in the UI, the “Prefect way” is to give each category/tenant its own distinct Flow object (i.e., a unique flow name). Here are clean patterns that achieve that while reusing your orchestrator logic.
Option A: Export per-tenant flow objects (YAML-friendly)
- Create a flow factory that returns a Flow configured for a tenant/category.
- Instantiate flows at module import time and export them as variables you can point to from YAML.
# src/core/pipeline/entrypoints.py
from prefect import flow
def get_tenant_orchestrator(tenant: str):
@flow(name=f"orchestrator-{tenant}")
def orchestrator():
# your generic logic here, using `tenant`
...
return orchestrator
# Export separate Flow objects; these are importable entrypoints
orch_mock = get_tenant_orchestrator("mock-tenant")
orch_acme = get_tenant_orchestrator("acme")
Then in prefect.yaml:
deployments:
- name: mock-deploy
entrypoint: src/core/pipeline/entrypoints.py:orch_mock
work_pool:
name: my-pool
- name: acme-deploy
entrypoint: src/core/pipeline/entrypoints.py:orch_acme
work_pool:
name: my-pool
Result: two different Flows in the UI (orchestrator-mock-tenant and orchestrator-acme), each with its own deployments.
Option B: Define thin wrappers that call a generic subflow
- Keep your generic logic in a subflow or tasks.
- Expose multiple top-level flows with different names that call the generic logic.
from prefect import flow
@flow
def generic_orchestrator(tenant: str):
...
@flow(name="orchestrator-mock-tenant")
def orchestrator_mock():
return generic_orchestrator("mock-tenant")
@flow(name="orchestrator-acme")
def orchestrator_acme():
return generic_orchestrator("acme")
YAML entrypoints:
entrypoint: src/core/pipeline/entrypoints.py:orchestrator_mock
entrypoint: src/core/pipeline/entrypoints.py:orchestrator_acme
Option C: Deploy via Python with a factory and serve
- Programmatically create flows and deployments. This is convenient when you have many tenants.
# deploy.py
from prefect import flow, serve
def create_orchestrator_flow(tenant: str):
@flow(name=f"orchestrator-{tenant}")
def orchestrator():
...
return orchestrator
if __name__ == "__main__":
orch_mock = create_orchestrator_flow("mock-tenant")
orch_acme = create_orchestrator_flow("acme")
serve(
orch_mock.to_deployment(name="default"),
orch_acme.to_deployment(name="default"),
)
Key points
- Entrypoints import objects only; they cannot call functions with arguments.
- Deployments are grouped under flows; to separate in the UI, you need distinct Flow objects (unique flow names).
- A factory that returns a flow (with a unique name) is a clean way to reuse logic while keeping flows separate.
- If you prefer YAML, export per-tenant Flow objects in your module and reference each by name.
Docs for reference:
- Deployments concept
- Define deployments with prefect.yaml
- Deploy via Python
- Run/serve multiple flows together
Would you prefer to stick with YAML-only, or are you open to managing deployments in Python with a small deploy script? I can tailor the example to your setup.