Acryl Executor
Acryl Executor is a Python library used internally by Acryl Agents and the DataHub ecosystem to define and execute modular tasks. It provides core abstractions like `BaseTask` and `Executor` for building extensible task-based workflows. As a sub-package of the larger DataHub project, its releases are often coupled with DataHub's evolution, though its own versioning is independent. The current version is 0.3.10, and it follows an active release cadence driven by DataHub development.
Common errors
-
TypeError: Can't instantiate abstract class MySimpleTask with abstract method execute
cause A class inheriting from `acryl.executor.sdk.tasks.base_task.BaseTask` must implement the `execute` method as defined in the abstract base class.fixEnsure your custom task class includes a definition for `def execute(self, config: Dict[str, Any]) -> TaskResult: ...` with the correct signature and return type. -
ModuleNotFoundError: No module named 'acryl.executor.sdk'
cause The `acryl-executor` library is not installed, or the import path is incorrect (e.g., trying `acryl_executor` instead of `acryl`).fixRun `pip install acryl-executor`. Verify all imports use `from acryl.executor...`. -
TypeError: execute_task() missing 1 required positional argument: 'config'
cause The `execute_task` method on `Executor` expects two arguments: a `BaseTask` instance and a `config` dictionary.fixEnsure you call `executor.execute_task(my_task_instance, {'key': 'value'})` providing a dictionary for task configuration, even if it's an empty dictionary.
Warnings
- gotcha Acryl Executor is primarily an internal library for the DataHub ecosystem. While available on PyPI, its public API (especially pre-1.0 versions like 0.x.x) may evolve rapidly with breaking changes that are not always explicitly documented for `acryl-executor` itself, but rather as part of broader DataHub releases.
- breaking Given `acryl-executor` is in its 0.x.x series, changes to `BaseTask` method signatures or `TaskResult` structure might occur in minor versions (e.g., `0.3.10` to `0.4.0`) without adhering to strict semantic versioning. This means a minor version bump could introduce breaking changes.
- gotcha The `Executor` provides synchronous task execution by default. For long-running or asynchronous tasks, `acryl-executor` is typically integrated with an external orchestration layer (e.g., DataHub Actions framework), which handles queuing, scheduling, and concurrency. Running `executor.execute_task()` directly will block the calling thread.
Install
-
pip install acryl-executor
Imports
- BaseTask
from acryl_executor.sdk.tasks.base_task import BaseTask
from acryl.executor.sdk.tasks.base_task import BaseTask
- TaskResult
from acryl.executor.sdk.tasks.base_task import TaskResult
- Executor
from acryl_executor.sdk.executor import Executor
from acryl.executor.sdk.executor import Executor
Quickstart
import os
from typing import Dict, Any, NamedTuple
from abc import ABC, abstractmethod
from acryl.executor.sdk.tasks.base_task import BaseTask, TaskResult
from acryl.executor.sdk.executor import Executor
class MySimpleTaskResult(NamedTuple):
status: str
message: str
class MySimpleTask(BaseTask):
def execute(self, config: Dict[str, Any]) -> MySimpleTaskResult:
name = config.get('name', 'World')
# Example of using an environment variable for configuration (e.g., for API keys)
secret_key = os.environ.get('MY_SECRET_KEY', 'default_secret')
print(f"Executing MySimpleTask for {name} with secret: {secret_key[:4]}...")
return MySimpleTaskResult(status='SUCCESS', message=f'Hello, {name}!')
# Configure with actual environment variable or a placeholder for quick run
os.environ['MY_SECRET_KEY'] = os.environ.get('MY_SECRET_KEY', 'some_default_value_for_testing')
# 1. Instantiate the Executor
executor = Executor()
# 2. Define a task instance
my_task = MySimpleTask()
# 3. Define task configuration
task_config = {"name": "DataHub User"}
# 4. Execute the task
print("\n--- Executing MySimpleTask ---")
result = executor.execute_task(my_task, task_config)
print(f"Task Result: {result.status}, Message: {result.message}")
# Example with different config
task_config_2 = {"name": "Acryl Team"}
print("\n--- Executing MySimpleTask with different config ---")
result_2 = executor.execute_task(my_task, task_config_2)
print(f"Task Result: {result_2.status}, Message: {result_2.message}")