Skip to content

Commit e7f22bc

Browse files
author
Nate Kupp
committed
Move Celery-K8s executor
Summary: Splits up executor.py to avoid the `@executor` invoking `celery_k8s_config()` at module import time Test Plan: bk Reviewers: schrockn Reviewed By: schrockn Differential Revision: https://dagster.phacility.com/D2839
1 parent 60c1251 commit e7f22bc

4 files changed

Lines changed: 134 additions & 126 deletions

File tree

.buildkite/images/docker/test_project/test_pipelines/test_pipelines/repo.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ def demo_pipeline():
5353

5454

5555
def define_demo_pipeline_celery():
56-
from dagster_celery import celery_executor, celery_k8s_job_executor
56+
from dagster_celery import celery_executor
57+
from dagster_celery.executor_k8s import celery_k8s_job_executor
5758

5859
@pipeline(
5960
mode_defs=[
@@ -117,7 +118,8 @@ def optional_outputs():
117118

118119

119120
def define_long_running_pipeline_celery():
120-
from dagster_celery import celery_executor, celery_k8s_job_executor
121+
from dagster_celery import celery_executor
122+
from dagster_celery.executor_k8s import celery_k8s_job_executor
121123

122124
@solid
123125
def long_running_task(context):
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .executor import celery_executor, celery_k8s_job_executor
1+
from .executor import celery_executor
Lines changed: 1 addition & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
from dagster import Field, Noneable, Permissive, StringSource
22
from dagster.core.definitions.executor import check_cross_process_constraints, executor
33
from dagster.core.execution.retries import Retries, get_retries_config
4-
from dagster.utils import merge_dicts
54

6-
from .config import CeleryConfig, CeleryK8sJobConfig
5+
from .config import CeleryConfig
76

87
CELERY_CONFIG = {
98
'broker': Field(
@@ -93,124 +92,3 @@ def celery_enabled_pipeline():
9392
include=init_context.executor_config.get('include'),
9493
retries=Retries.from_config(init_context.executor_config['retries']),
9594
)
96-
97-
98-
def celery_k8s_config():
99-
from dagster_k8s.job import DagsterK8sJobConfig
100-
101-
# DagsterK8sJobConfig provides config schema for specifying Dagster K8s Jobs
102-
job_config = DagsterK8sJobConfig.config_type()
103-
104-
additional_config = {
105-
'load_incluster_config': Field(
106-
bool,
107-
is_required=False,
108-
default_value=True,
109-
description='''Set this value if you are running the launcher within a k8s cluster. If
110-
``True``, we assume the launcher is running within the target cluster and load config
111-
using ``kubernetes.config.load_incluster_config``. Otherwise, we will use the k8s config
112-
specified in ``kubeconfig_file`` (using ``kubernetes.config.load_kube_config``) or fall
113-
back to the default kubeconfig. Default: ``True``.''',
114-
),
115-
'kubeconfig_file': Field(
116-
Noneable(str),
117-
is_required=False,
118-
description='Path to a kubeconfig file to use, if not using default kubeconfig.',
119-
),
120-
'job_namespace': Field(
121-
str,
122-
is_required=False,
123-
default_value='default',
124-
description='The namespace into which to launch new jobs. Note that any '
125-
'other Kubernetes resources the Job requires (such as the service account) must be '
126-
'present in this namespace. Default: ``"default"``',
127-
),
128-
}
129-
130-
cfg = merge_dicts(CELERY_CONFIG, job_config)
131-
cfg = merge_dicts(cfg, additional_config)
132-
return cfg
133-
134-
135-
@executor(name='celery-k8s', config=celery_k8s_config())
136-
def celery_k8s_job_executor(init_context):
137-
'''Celery-based executor which launches tasks as Kubernetes Jobs.
138-
139-
The Celery executor exposes config settings for the underlying Celery app under
140-
the ``config_source`` key. This config corresponds to the "new lowercase settings" introduced
141-
in Celery version 4.0 and the object constructed from config will be passed to the
142-
:py:class:`celery.Celery` constructor as its ``config_source`` argument.
143-
(See https://docs.celeryproject.org/en/latest/userguide/configuration.html for details.)
144-
145-
The executor also exposes the ``broker``, `backend`, and ``include`` arguments to the
146-
:py:class:`celery.Celery` constructor.
147-
148-
In the most common case, you may want to modify the ``broker`` and ``backend`` (e.g., to use
149-
Redis instead of RabbitMQ). We expect that ``config_source`` will be less frequently
150-
modified, but that when solid executions are especially fast or slow, or when there are
151-
different requirements around idempotence or retry, it may make sense to execute pipelines
152-
with variations on these settings.
153-
154-
If you'd like to configure a Celery Kubernetes Job executor in addition to the
155-
:py:class:`~dagster.default_executors`, you should add it to the ``executor_defs`` defined on a
156-
:py:class:`~dagster.ModeDefinition` as follows:
157-
158-
.. code-block:: python
159-
160-
from dagster import ModeDefinition, default_executors, pipeline
161-
from dagster_celery import celery_k8s_job_executor
162-
163-
@pipeline(mode_defs=[
164-
ModeDefinition(executor_defs=default_executors + [celery_k8s_job_executor])
165-
])
166-
def celery_enabled_pipeline():
167-
pass
168-
169-
Then you can configure the executor as follows:
170-
171-
.. code-block:: YAML
172-
173-
execution:
174-
celery-k8s:
175-
config:
176-
job_image: 'my_repo.com/image_name:latest'
177-
job_namespace: 'some-namespace'
178-
broker: 'pyamqp://guest@localhost//' # Optional[str]: The URL of the Celery broker
179-
backend: 'rpc://' # Optional[str]: The URL of the Celery results backend
180-
include: ['my_module'] # Optional[List[str]]: Modules every worker should import
181-
config_source: # Dict[str, Any]: Any additional parameters to pass to the
182-
#... # Celery workers. This dict will be passed as the `config_source`
183-
#... # argument of celery.Celery().
184-
185-
Note that the YAML you provide here must align with the configuration with which the Celery
186-
workers on which you hope to run were started. If, for example, you point the executor at a
187-
different broker than the one your workers are listening to, the workers will never be able to
188-
pick up tasks for execution.
189-
'''
190-
from dagster_k8s.job import DagsterK8sJobConfig
191-
192-
check_cross_process_constraints(init_context)
193-
194-
job_config = DagsterK8sJobConfig(
195-
job_image=init_context.executor_config.get('job_image'),
196-
dagster_home=init_context.executor_config.get('dagster_home'),
197-
image_pull_policy=init_context.executor_config.get('image_pull_policy'),
198-
image_pull_secrets=init_context.executor_config.get('image_pull_secrets'),
199-
service_account_name=init_context.executor_config.get('service_account_name'),
200-
instance_config_map=init_context.executor_config.get('instance_config_map'),
201-
postgres_password_secret=init_context.executor_config.get('postgres_password_secret'),
202-
env_config_maps=init_context.executor_config.get('env_config_maps'),
203-
env_secrets=init_context.executor_config.get('env_secrets'),
204-
)
205-
206-
return CeleryK8sJobConfig(
207-
broker=init_context.executor_config.get('broker'),
208-
backend=init_context.executor_config.get('backend'),
209-
config_source=init_context.executor_config.get('config_source'),
210-
include=init_context.executor_config.get('include'),
211-
retries=Retries.from_config(init_context.executor_config['retries']),
212-
job_config=job_config,
213-
job_namespace=init_context.executor_config.get('job_namespace'),
214-
load_incluster_config=init_context.executor_config.get('load_incluster_config'),
215-
kubeconfig_file=init_context.executor_config.get('kubeconfig_file'),
216-
)
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
from dagster import Field, Noneable
2+
from dagster.core.definitions.executor import check_cross_process_constraints, executor
3+
from dagster.core.execution.retries import Retries
4+
from dagster.utils import merge_dicts
5+
6+
from .config import CeleryK8sJobConfig
7+
from .executor import CELERY_CONFIG
8+
9+
10+
def celery_k8s_config():
11+
from dagster_k8s.job import DagsterK8sJobConfig
12+
13+
# DagsterK8sJobConfig provides config schema for specifying Dagster K8s Jobs
14+
job_config = DagsterK8sJobConfig.config_type()
15+
16+
additional_config = {
17+
'load_incluster_config': Field(
18+
bool,
19+
is_required=False,
20+
default_value=True,
21+
description='''Set this value if you are running the launcher within a k8s cluster. If
22+
``True``, we assume the launcher is running within the target cluster and load config
23+
using ``kubernetes.config.load_incluster_config``. Otherwise, we will use the k8s config
24+
specified in ``kubeconfig_file`` (using ``kubernetes.config.load_kube_config``) or fall
25+
back to the default kubeconfig. Default: ``True``.''',
26+
),
27+
'kubeconfig_file': Field(
28+
Noneable(str),
29+
is_required=False,
30+
description='Path to a kubeconfig file to use, if not using default kubeconfig.',
31+
),
32+
'job_namespace': Field(
33+
str,
34+
is_required=False,
35+
default_value='default',
36+
description='The namespace into which to launch new jobs. Note that any '
37+
'other Kubernetes resources the Job requires (such as the service account) must be '
38+
'present in this namespace. Default: ``"default"``',
39+
),
40+
}
41+
42+
cfg = merge_dicts(CELERY_CONFIG, job_config)
43+
cfg = merge_dicts(cfg, additional_config)
44+
return cfg
45+
46+
47+
@executor(name='celery-k8s', config=celery_k8s_config())
48+
def celery_k8s_job_executor(init_context):
49+
'''Celery-based executor which launches tasks as Kubernetes Jobs.
50+
51+
The Celery executor exposes config settings for the underlying Celery app under
52+
the ``config_source`` key. This config corresponds to the "new lowercase settings" introduced
53+
in Celery version 4.0 and the object constructed from config will be passed to the
54+
:py:class:`celery.Celery` constructor as its ``config_source`` argument.
55+
(See https://docs.celeryproject.org/en/latest/userguide/configuration.html for details.)
56+
57+
The executor also exposes the ``broker``, `backend`, and ``include`` arguments to the
58+
:py:class:`celery.Celery` constructor.
59+
60+
In the most common case, you may want to modify the ``broker`` and ``backend`` (e.g., to use
61+
Redis instead of RabbitMQ). We expect that ``config_source`` will be less frequently
62+
modified, but that when solid executions are especially fast or slow, or when there are
63+
different requirements around idempotence or retry, it may make sense to execute pipelines
64+
with variations on these settings.
65+
66+
If you'd like to configure a Celery Kubernetes Job executor in addition to the
67+
:py:class:`~dagster.default_executors`, you should add it to the ``executor_defs`` defined on a
68+
:py:class:`~dagster.ModeDefinition` as follows:
69+
70+
.. code-block:: python
71+
72+
from dagster import ModeDefinition, default_executors, pipeline
73+
from dagster_celery.executor_k8s import celery_k8s_job_executor
74+
75+
@pipeline(mode_defs=[
76+
ModeDefinition(executor_defs=default_executors + [celery_k8s_job_executor])
77+
])
78+
def celery_enabled_pipeline():
79+
pass
80+
81+
Then you can configure the executor as follows:
82+
83+
.. code-block:: YAML
84+
85+
execution:
86+
celery-k8s:
87+
config:
88+
job_image: 'my_repo.com/image_name:latest'
89+
job_namespace: 'some-namespace'
90+
broker: 'pyamqp://guest@localhost//' # Optional[str]: The URL of the Celery broker
91+
backend: 'rpc://' # Optional[str]: The URL of the Celery results backend
92+
include: ['my_module'] # Optional[List[str]]: Modules every worker should import
93+
config_source: # Dict[str, Any]: Any additional parameters to pass to the
94+
#... # Celery workers. This dict will be passed as the `config_source`
95+
#... # argument of celery.Celery().
96+
97+
Note that the YAML you provide here must align with the configuration with which the Celery
98+
workers on which you hope to run were started. If, for example, you point the executor at a
99+
different broker than the one your workers are listening to, the workers will never be able to
100+
pick up tasks for execution.
101+
'''
102+
from dagster_k8s.job import DagsterK8sJobConfig
103+
104+
check_cross_process_constraints(init_context)
105+
106+
job_config = DagsterK8sJobConfig(
107+
job_image=init_context.executor_config.get('job_image'),
108+
dagster_home=init_context.executor_config.get('dagster_home'),
109+
image_pull_policy=init_context.executor_config.get('image_pull_policy'),
110+
image_pull_secrets=init_context.executor_config.get('image_pull_secrets'),
111+
service_account_name=init_context.executor_config.get('service_account_name'),
112+
instance_config_map=init_context.executor_config.get('instance_config_map'),
113+
postgres_password_secret=init_context.executor_config.get('postgres_password_secret'),
114+
env_config_maps=init_context.executor_config.get('env_config_maps'),
115+
env_secrets=init_context.executor_config.get('env_secrets'),
116+
)
117+
118+
return CeleryK8sJobConfig(
119+
broker=init_context.executor_config.get('broker'),
120+
backend=init_context.executor_config.get('backend'),
121+
config_source=init_context.executor_config.get('config_source'),
122+
include=init_context.executor_config.get('include'),
123+
retries=Retries.from_config(init_context.executor_config['retries']),
124+
job_config=job_config,
125+
job_namespace=init_context.executor_config.get('job_namespace'),
126+
load_incluster_config=init_context.executor_config.get('load_incluster_config'),
127+
kubeconfig_file=init_context.executor_config.get('kubeconfig_file'),
128+
)

0 commit comments

Comments
 (0)