Task¶
A Task is a finite executable — wired through dependency injection the same way as a
Component, but with a single execute() contract the Context calls
once. It represents a bounded unit of work that runs once, produces a result, and
completes. Unlike a Service, it does not run indefinitely. Unlike a
Pipeline, it does not coordinate other tasks.
Tasks answer one question:
What work needs doing, once?
When to use Task¶
Use @Task when a class needs to:
- perform a single, well-defined unit of work
- optionally produce a result
- run to completion and stop
Typical examples:
- fetching data from an external source
- generating a report
- training or evaluating a model
- sending a notification
- exporting data to storage
Decorator¶
The @Task decorator registers the class into the Task namespace as a finite
executable component. The Context reads from this namespace at startup. The class
is returned unchanged.
Without arguments¶
With a name¶
Combined with a Layer¶
Interface¶
A Task implements a single method — execute(). It may return a value or None.
@Task
class MetricsFetcher:
def execute(self):
# perform the work
# return a result, or None if the task has only side effects
...
Dependency Injection¶
Like all components, a Task declares its dependencies through the constructor:
@Analytics
@Task
class MetricsFetcher:
def __init__(
self,
config: Config,
metrics: Metrics,
):
self.config = config
self.metrics = metrics
def execute(self):
data = self._fetch(self.config.source_url)
self.metrics.save(data)
return data
def _fetch(self, url):
...
Full Examples¶
Data collection¶
@Analytics
@Task
class MetricsFetcher:
def __init__(
self,
config: Config,
metrics: Metrics,
):
self.config = config
self.metrics = metrics
def execute(self):
data = self._fetch(self.config.source_url)
self.metrics.save(data)
return data
def _fetch(self, url):
...
Model training¶
@Analytics
@Task
class ModelTrainer:
def __init__(
self,
config: Config,
classifier: Classifier,
metrics: Metrics,
):
self.config = config
self.classifier = classifier
self.metrics = metrics
def execute(self):
data = self.metrics.load(self.config.training_dataset)
self.classifier.fit(data)
Report generation¶
@Analytics
@Task
class ReportGenerator:
def __init__(
self,
config: Config,
metrics: Metrics,
):
self.config = config
self.metrics = metrics
def execute(self):
data = self.metrics.load(self.config.report_period)
report = self._build(data)
self._export(report, self.config.output_path)
return report
def _build(self, data):
...
def _export(self, report, path):
...
Using a Task¶
A Task is resolved and executed through the Context, by class name:
Or directly within a Pipeline that coordinates multiple tasks:
@Pipeline
class DailyAnalytics:
def __init__(
self,
fetcher: MetricsFetcher,
trainer: ModelTrainer,
report: ReportGenerator,
):
self.fetcher = fetcher
self.trainer = trainer
self.report = report
def execute(self):
self.fetcher.execute()
self.trainer.execute()
return self.report.execute()
Protocol¶
TaskProtocol documents the expected interface and is available for type checking
and introspection:
from opendataframework import TaskProtocol
isinstance(instance, TaskProtocol) # True if execute() is present
TaskProtocol is @runtime_checkable. The Context uses it to verify that a
registered class implements execute() before calling it.
What Task is Not¶
-
Not a long-running process. A
Taskruns to completion. If the work needs to run indefinitely, use a Service. -
Not an orchestrator. If the work involves coordinating multiple tasks, use a Pipeline.
-
Not required to return a value.
execute()may returnNonewhen the task produces only side effects — saving to storage, sending a notification, writing a file. -
Not a base class.
MetricsFetcherdoes not inherit fromTask. The decorator registers it; inheritance is not involved.
Decision Guide¶
| I need to... | Use |
|---|---|
| Provide a reusable capability | Component |
| Run a process indefinitely | Service |
| Execute a bounded unit of work once | Task |
| Coordinate multiple tasks into a workflow | Pipeline |
| Manage persistent data | Repository |