Skip to content

Commit b7712f3

Browse files
committed
Add simple & supported way to setup MRQ's context. Fixes #51
1 parent 8d2c86a commit b7712f3

9 files changed

Lines changed: 54 additions & 18 deletions

File tree

docs/memory-leaks.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ First, initialize a REPL with MRQ configured and guppy loaded:
2020
```
2121
$ pip install guppy
2222
$ python
23-
>>> from mrq import config
24-
>>> from mrq.context import set_current_config, run_task
25-
>>> set_current_config(config.get_config(sources=("file", "env"), config_type="run"))
23+
>>> from mrq.context import setup_context, run_task
24+
>>> setup_context()
2625
>>> from guppy import hpy
2726
>>> hp = hpy()
2827
```

mrq/bin/mrq_run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def main():
2727

2828
parser = argparse.ArgumentParser(description='Runs a task')
2929

30-
cfg = config.get_config(parser=parser, config_type="run")
30+
cfg = config.get_config(parser=parser, config_type="run", sources=("file", "env", "args"))
3131
cfg["is_cli"] = True
3232
set_current_config(cfg)
3333

mrq/bin/mrq_worker.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@
2121

2222
from mrq import config
2323
from mrq.utils import load_class_by_path
24+
from mrq.context import set_current_config
2425

2526

2627
def main():
2728

2829
parser = argparse.ArgumentParser(description='Start a RQ worker')
2930

30-
cfg = config.get_config(parser=parser, config_type="worker")
31+
cfg = config.get_config(parser=parser, config_type="worker", sources=("file", "env", "args"))
3132

3233
# If we are launching with a --processes option and without the SUPERVISOR_ENABLED env
3334
# then we should just call supervisord.
@@ -100,7 +101,9 @@ def sigterm_handler(signum, frame): # pylint: disable=unused-argument
100101

101102
worker_class = load_class_by_path(cfg["worker_class"])
102103

103-
w = worker_class(cfg)
104+
set_current_config(cfg)
105+
106+
w = worker_class()
104107

105108
exitcode = w.work_loop()
106109

mrq/config.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,11 @@ def add_parser_args(parser, config_type):
300300
def get_config(
301301
sources=(
302302
"file",
303-
"env",
304-
"args"),
303+
"env"),
305304
env_prefix="MRQ_",
306305
file_path=None,
307306
parser=None,
308-
config_type="worker"):
307+
config_type=None):
309308
""" Returns a config dict merged from several possible sources """
310309

311310
if not parser:
@@ -314,7 +313,7 @@ def get_config(
314313
add_parser_args(parser, config_type)
315314

316315
if config_type in ["run"]:
317-
default_config = parser.parse_args(["x"]).__dict__
316+
default_config = parser.parse_args(["notask"]).__dict__
318317
else:
319318
default_config = parser.parse_args([]).__dict__
320319

mrq/context.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import time
77
from .utils import LazyObject, load_class_by_path, group_iter
88
from itertools import count as itertools_count
9+
from .config import get_config
910

11+
# This should be MRQ's only Python object shared by all the jobs in the same process
1012
_GLOBAL_CONTEXT = {
1113

1214
# Contains all the running greenlets for this worker. greenletid => Job object
@@ -19,10 +21,18 @@
1921
"config": None
2022
}
2123

22-
# Global log object, usable from all tasks
24+
# Global log object, usable from all jobs
2325
log = Logger(None, job="current")
2426

2527

28+
def setup_context(**kwargs):
29+
""" Setup MRQ's environment.
30+
31+
Note: gevent should probably be initialized too if you want to use concurrency.
32+
"""
33+
set_current_config(get_config(**kwargs))
34+
35+
2636
def set_current_job(job):
2737
current = gevent.getcurrent()
2838

@@ -44,7 +54,6 @@ def get_current_job(greenlet_id=None):
4454

4555
def set_current_worker(worker):
4656
_GLOBAL_CONTEXT["worker"] = worker
47-
set_current_config(worker.config)
4857

4958

5059
def get_current_worker():

mrq/dashboard/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
parser = argparse.ArgumentParser(description='Start the MRQ dashboard')
2626

27-
cfg = get_config(parser=parser, config_type="dashboard")
27+
cfg = get_config(parser=parser, config_type="dashboard", sources=("file", "env", "args"))
2828
set_current_config(cfg)
2929

3030
app = Flask(

mrq/worker.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .job import Job
1717
from .exceptions import (TimeoutInterrupt, StopRequested, JobInterrupt, AbortInterrupt,
1818
RetryInterrupt, MaxRetriesInterrupt)
19-
from .context import (set_current_worker, set_current_job, get_current_job,
19+
from .context import (set_current_worker, set_current_job, get_current_job, get_current_config,
2020
connections, enable_greenlet_tracing)
2121
from .queue import Queue
2222

@@ -35,9 +35,7 @@ class Worker(object):
3535
mongodb_logs = None
3636
redis = None
3737

38-
def __init__(self, config):
39-
40-
self.config = config
38+
def __init__(self):
4139

4240
set_current_worker(self)
4341

@@ -57,7 +55,7 @@ def __init__(self, config):
5755
self.graceful_stop = None
5856

5957
self.id = ObjectId()
60-
if config["name"]:
58+
if self.config.get("name"):
6159
self.name = self.config["name"]
6260
else:
6361
# Generate a somewhat human-readable name for this worker
@@ -85,6 +83,10 @@ def __init__(self, config):
8583
"total": 0
8684
}
8785

86+
@property
87+
def config(self):
88+
return get_current_config()
89+
8890
def connect(self, force=False):
8991

9092
if self.connected and not force:
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from mrq.context import setup_context, run_task, get_current_config
2+
3+
# Autoconfigure MRQ's environment
4+
setup_context()
5+
6+
print run_task("tests.tasks.general.Add", {"a": 41, "b": 1})
7+
8+
print get_current_config()["name"]

tests/test_context.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import time
3+
import os
34

45

56
def test_context_get(worker):
@@ -80,3 +81,18 @@ def test_context_metric_failed(worker):
8081
assert metrics.get("jobs.status.started") == 2
8182
assert metrics.get("jobs.status.failed") == 1
8283
assert metrics.get("jobs.status.success") is None
84+
85+
86+
def test_context_setup():
87+
88+
try:
89+
import subprocess32 as subprocess
90+
except:
91+
import subprocess
92+
93+
process = subprocess.Popen("python tests/fixtures/standalone_script1.py",
94+
shell=True, close_fds=True, env={"MRQ_NAME": "testname1", "PYTHONPATH": os.getcwd()}, cwd=os.getcwd(), stdout=subprocess.PIPE)
95+
96+
out, err = process.communicate()
97+
98+
assert out.endswith("42\ntestname1\n")

0 commit comments

Comments
 (0)