Skip to content

Commit 2df7bb1

Browse files
committed
update doc; fix bug
1 parent 097eb54 commit 2df7bb1

File tree

9 files changed

+219
-80
lines changed

9 files changed

+219
-80
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ By harnessing the capabilities of Executor Engine, users can effortlessly constr
3232

3333
+ 📚 Support multiple job types
3434
* `LocalJob`, `ThreadJob`, `ProcessJob`, `DaskJob`
35-
* Extend job types: `SubprocessJob`, `WebappJob`
35+
* Extend job types: `SubprocessJob`, `WebappJob`, `CronJob`
3636
+ 🔧 Job management
3737
* Job dependency management.
3838
* Job status: Pending, Running, Done, Failed, Cancelled.

docs/api-reference/condition.md

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,57 @@
1515
options:
1616
show_root_heading: true
1717

18-
::: executor.engine.job.condition.AfterTimepoint
18+
::: executor.engine.job.condition.Combination
1919
handler: python
2020
options:
2121
show_root_heading: true
2222

23-
::: executor.engine.job.condition.Combination
23+
::: executor.engine.job.condition.AllSatisfied
2424
handler: python
2525
options:
2626
show_root_heading: true
2727

28-
::: executor.engine.job.condition.AllSatisfied
28+
::: executor.engine.job.condition.AnySatisfied
2929
handler: python
3030
options:
3131
show_root_heading: true
3232

33-
::: executor.engine.job.condition.AnySatisfied
33+
::: executor.engine.job.condition.TimeCondition
34+
handler: python
35+
options:
36+
show_root_heading: true
37+
38+
::: executor.engine.job.condition.EveryPeriod
39+
handler: python
40+
options:
41+
show_root_heading: true
42+
43+
::: executor.engine.job.condition.AfterClock
44+
handler: python
45+
options:
46+
show_root_heading: true
47+
48+
::: executor.engine.job.condition.BeforeClock
49+
handler: python
50+
options:
51+
show_root_heading: true
52+
53+
::: executor.engine.job.condition.AfterWeekday
54+
handler: python
55+
options:
56+
show_root_heading: true
57+
58+
::: executor.engine.job.condition.BeforeWeekday
59+
handler: python
60+
options:
61+
show_root_heading: true
62+
63+
::: executor.engine.job.condition.AfterTimepoint
64+
handler: python
65+
options:
66+
show_root_heading: true
67+
68+
::: executor.engine.job.condition.BeforeTimepoint
3469
handler: python
3570
options:
3671
show_root_heading: true

docs/api-reference/extend_job.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,15 @@
88
::: executor.engine.job.extend.WebappJob
99
handler: python
1010
options:
11-
show_root_heading: true
11+
show_root_heading: true
12+
13+
::: executor.engine.job.extend.SentinelJob
14+
handler: python
15+
options:
16+
show_root_heading: true
17+
18+
::: executor.engine.job.extend.CronJob
19+
handler: python
20+
options:
21+
show_root_heading: true
22+

docs/getting-started.md

Lines changed: 159 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ engine = Engine()
4545
def add(a, b):
4646
return a + b
4747

48+
async def add_async(a, b):
49+
# async function can also be used as the job function
50+
await asyncio.sleep(1.0)
51+
return a + b
52+
4853
async def main():
49-
job1 = ProcessJob(add, args=(1, 2))
54+
job1 = ProcessJob(add_async, args=(1, 2))
5055
job2 = ProcessJob(add, args=(job1.future, 4))
5156
await engine.submit_async(job1, job2)
5257
await engine.join()
@@ -96,73 +101,6 @@ They are executed by different backends and suitable for different scenarios.
96101
| `ProcessJob` | `executor.engine.backend.process` | CPU-bound tasks |
97102
| `DaskJob` | `executor.engine.backend.dask` | Distributed tasks |
98103

99-
### Extend job types
100-
101-
There are two extend job types:
102-
[`SubprocessJob`](api-reference/extend_job.md#executor.engine.job.extend.SubprocessJob)
103-
and
104-
[`WebappJob`](api-reference/extend_job.md#executor.engine.job.extend.WebappJob)
105-
. They are used to execute shell commands and launch web applications.
106-
The extend job types can based on the job types above(`LocalJob`, `ThreadJob`, `ProcessJob`, `DaskJob`).
107-
108-
#### SubprocessJob
109-
110-
[`SubprocessJob`](api-reference/extend_job.md#executor.engine.job.extend.SubprocessJob)
111-
is a job type for executing shell commands.
112-
`SubprocessJob` accept a shell command as its argument. It will execute the command in a subprocess:
113-
114-
```python
115-
from executor.engine import Engine
116-
from executor.engine.job.extend import SubprocessJob
117-
118-
job = SubprocessJob(
119-
"python -c 'print(1 + 2)'",
120-
)
121-
122-
with Engine() as engine:
123-
engine.submit(job)
124-
engine.wait_job(job)
125-
```
126-
127-
128-
#### WebappJob
129-
130-
[`WebappJob`](api-reference/extend_job.md#executor.engine.job.extend.WebappJob)
131-
is a job type for launching a web application.
132-
It can accept a function with `ip` and `port` as arguments:
133-
134-
```python
135-
from executor.engine import Engine
136-
from executor.engine.job.extend import WebappJob
137-
from http.server import HTTPServer, SimpleHTTPRequestHandler
138-
139-
def run_simple_httpd(ip: str, port: int):
140-
server_addr = (ip, port)
141-
httpd = HTTPServer(server_addr, SimpleHTTPRequestHandler)
142-
httpd.serve_forever()
143-
144-
with Engine() as engine:
145-
job = WebappJob(run_simple_httpd, ip="127.0.0.1", port=8000)
146-
engine.submit(job)
147-
print("Open your browser and visit http://127.0.0.1:8000")
148-
engine.wait()
149-
```
150-
151-
`WebappJob` can also accept a command template as its argument:
152-
153-
```python
154-
from executor.engine import Engine
155-
from executor.engine.job.extend import WebappJob
156-
157-
with Engine() as engine:
158-
job = WebappJob(
159-
"python -m http.server -b {ip} {port}",
160-
ip="127.0.0.1", port=8000)
161-
engine.submit(job)
162-
print("Open your browser and visit http://127.0.0.1:8000")
163-
engine.wait()
164-
```
165-
166104
### Conditional job execution
167105

168106
After another job:
@@ -284,6 +222,42 @@ with Engine() as engine:
284222
engine.wait()
285223
```
286224

225+
##### Syntactic sugar for condition combination
226+
227+
You can use `&` and `|` to combine conditions:
228+
229+
```python
230+
from executor.engine import Engine, ThreadJob
231+
from executor.engine.job.condition import AfterAnother
232+
import time
233+
234+
s = set()
235+
236+
def sleep_and_add_1(t: int):
237+
time.sleep(t)
238+
s.add(t)
239+
240+
def has_two_elements():
241+
print(s)
242+
assert len(s) == 2
243+
244+
with Engine() as engine:
245+
job1 = ThreadJob(sleep_and_add_1, args=(1,))
246+
job2 = ThreadJob(sleep_and_add_1, args=(2,))
247+
job3 = ThreadJob(sleep_and_add_1, args=(3,))
248+
job4 = ThreadJob(
249+
has_two_elements,
250+
condition=(
251+
(
252+
AfterAnother(job_id=job1.id) &
253+
AfterAnother(job_id=job2.id)
254+
) |
255+
AfterAnother(job_id=job3.id)
256+
)
257+
)
258+
engine.submit(job4, job3, job2, job1)
259+
engine.wait()
260+
```
287261

288262
#### Custom condition
289263

@@ -319,6 +293,123 @@ with Engine() as engine:
319293
engine.wait()
320294
```
321295

296+
### Extend job types
297+
298+
There are 4 extend job types:
299+
[`SubprocessJob`](api-reference/extend_job.md#executor.engine.job.extend.SubprocessJob),
300+
[`WebappJob`](api-reference/extend_job.md#executor.engine.job.extend.WebappJob)
301+
[`SentinelJob`](api-reference/extend_job.md#executor.engine.job.extend.SentinelJob)
302+
[`CronJob`](api-reference/extend_job.md#executor.engine.job.extend.CronJob)
303+
304+
They are used to execute shell commands, launch web applications
305+
and schedule jobs based on time. The extend job types can based on the job types above(`LocalJob`, `ThreadJob`, `ProcessJob`, `DaskJob`).
306+
307+
#### SubprocessJob
308+
309+
[`SubprocessJob`](api-reference/extend_job.md#executor.engine.job.extend.SubprocessJob)
310+
is a job type for executing shell commands.
311+
`SubprocessJob` accept a shell command as its argument. It will execute the command in a subprocess:
312+
313+
```python
314+
from executor.engine import Engine
315+
from executor.engine.job.extend import SubprocessJob
316+
317+
job = SubprocessJob(
318+
"python -c 'print(1 + 2)'",
319+
)
320+
321+
with Engine() as engine:
322+
engine.submit(job)
323+
engine.wait_job(job)
324+
```
325+
326+
327+
#### WebappJob
328+
329+
[`WebappJob`](api-reference/extend_job.md#executor.engine.job.extend.WebappJob)
330+
is a job type for launching a web application.
331+
It can accept a function with `ip` and `port` as arguments:
332+
333+
```python
334+
from executor.engine import Engine
335+
from executor.engine.job.extend import WebappJob
336+
from http.server import HTTPServer, SimpleHTTPRequestHandler
337+
338+
def run_simple_httpd(ip: str, port: int):
339+
server_addr = (ip, port)
340+
httpd = HTTPServer(server_addr, SimpleHTTPRequestHandler)
341+
httpd.serve_forever()
342+
343+
with Engine() as engine:
344+
job = WebappJob(run_simple_httpd, ip="127.0.0.1", port=8000)
345+
engine.submit(job)
346+
print("Open your browser and visit http://127.0.0.1:8000")
347+
engine.wait()
348+
```
349+
350+
`WebappJob` can also accept a command template as its argument:
351+
352+
```python
353+
from executor.engine import Engine
354+
from executor.engine.job.extend import WebappJob
355+
356+
with Engine() as engine:
357+
job = WebappJob(
358+
"python -m http.server -b {ip} {port}",
359+
ip="127.0.0.1", port=8000)
360+
engine.submit(job)
361+
print("Open your browser and visit http://127.0.0.1:8000")
362+
engine.wait()
363+
```
364+
365+
#### CronJob
366+
367+
[`CronJob`](api-reference/extend_job.md#executor.engine.job.extend.CronJob)
368+
is a job type for scheduling jobs periodically.
369+
It should be used with different `TimeCondition` for different scheduling strategies. For example:
370+
371+
```python
372+
from executor.engine import Engine
373+
from executor.engine.job.extend.cron import (
374+
CronJob, every,
375+
hourly, daily, weekly,
376+
after_clock, between_clock,
377+
after_weekday,
378+
)
379+
380+
381+
def do_something():
382+
print("hello")
383+
384+
385+
with Engine() as engine:
386+
# will run the function every 10 seconds
387+
job1 = CronJob(do_something, every("10s"))
388+
# will run the function every minute
389+
job2 = CronJob(do_something, every("1m"))
390+
# will run the function every hour
391+
job3 = CronJob(do_something, hourly)
392+
# will run the function every day at 12:00
393+
job4 = CronJob(do_something, daily & after_clock("12:00"))
394+
# will run the function every week on Monday at 12:00
395+
job5 = CronJob(
396+
do_something,
397+
weekly & after_weekday("Monday") & after_clock("12:00"))
398+
# will run the function every 5min at the night
399+
job6 = CronJob(do_something, every("5m") & between_clock("18:00", "24:00"))
400+
engine.submit(job1, job2, job3, job4, job5, job6)
401+
engine.wait()
402+
```
403+
404+
See [CronJob](api-reference/extend_job.md#executor.engine.job.extend.CronJob) for more details.
405+
406+
!!! info
407+
`CronJob` is a special kind of
408+
[`SentinelJob`](api-reference/extend_job.md#executor.engine.job.extend.SentinelJob),
409+
`SentinelJob` is a more general kind of job, it will be
410+
submit other jobs when the condition is satisfied.
411+
412+
322413
### Generator support
323414

324415
`executor.engine` supports generator job, which is a special job that returns a generator.

executor/engine/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .core import Engine, EngineSetting
22
from .job import LocalJob, ThreadJob, ProcessJob
33

4-
__version__ = '0.2.9'
4+
__version__ = '0.3.0'
55

66
__all__ = [
77
'Engine', 'EngineSetting',

executor/engine/job/condition.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class EveryPeriod(TimeCondition):
187187
"""
188188
period_str: str
189189
last_submitted_at: T.Optional[datetime] = None
190-
immediate: bool = True
190+
immediate: bool = False
191191

192192
def satisfy(self, _) -> bool:
193193
period = _parse_period_str(self.period_str)
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from .subprocess import SubprocessJob
22
from .webapp import WebappJob
3+
from .sentinel import SentinelJob
4+
from .cron import CronJob
35

46

5-
__all__ = ["SubprocessJob", "WebappJob"]
7+
__all__ = ["SubprocessJob", "WebappJob", "SentinelJob", "CronJob"]

executor/engine/job/extend/cron.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
every = EveryPeriod
1515
daily = EveryPeriod("1d")
16+
weekly = EveryPeriod("7d")
1617
hourly = EveryPeriod("1h")
17-
monthly = EveryPeriod("1m")
1818

1919
before_clock = BeforeClock
2020
after_clock = AfterClock

executor/engine/job/extend/sentinel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ def SentinelJob(
4343
else:
4444
base_class = job_type
4545

46-
async def submitter(__engine__: "Engine"):
46+
async def sentinel(__engine__: "Engine"):
4747
while True:
4848
if sentinel_condition.satisfy(__engine__):
4949
job = base_class(func, **attrs)
5050
await __engine__.submit_async(job)
5151
await asyncio.sleep(time_delta)
5252

5353
sentinel_job = LocalJob(
54-
submitter,
54+
sentinel,
5555
**sentinel_attrs
5656
)
5757
return sentinel_job

0 commit comments

Comments
 (0)