ddeutil-workflow 0.0.7__py3-none-any.whl → 0.0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- __version__: str = "0.0.7"
1
+ __version__: str = "0.0.9"
@@ -10,22 +10,11 @@ from .exceptions import (
10
10
  StageException,
11
11
  UtilException,
12
12
  )
13
- from .on import AwsOn, On
14
- from .pipeline import Job, Pipeline
15
- from .stage import (
16
- BashStage,
17
- EmptyStage,
18
- HookStage,
19
- PyStage,
20
- Stage,
21
- TriggerStage,
22
- )
13
+ from .on import On, interval2crontab
14
+ from .pipeline import Job, Pipeline, Strategy
15
+ from .stage import Stage, handler_result
23
16
  from .utils import (
24
- ChoiceParam,
25
- DatetimeParam,
26
- IntParam,
27
17
  Param,
28
- StrParam,
29
18
  dash2underscore,
30
19
  param2template,
31
20
  )
ddeutil/workflow/api.py CHANGED
@@ -6,104 +6,62 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import asyncio
9
- import queue
10
- import time
9
+ import logging
10
+ import os
11
11
  import uuid
12
- from contextlib import asynccontextmanager
13
- from datetime import datetime
14
-
15
- from apscheduler.executors.pool import ProcessPoolExecutor
16
- from apscheduler.jobstores.memory import MemoryJobStore
17
- from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
18
- from apscheduler.schedulers.asyncio import AsyncIOScheduler
19
- from fastapi import BackgroundTasks, FastAPI
12
+ from queue import Empty, Queue
13
+
14
+ from ddeutil.core import str2bool
15
+ from dotenv import load_dotenv
16
+ from fastapi import FastAPI
20
17
  from fastapi.middleware.gzip import GZipMiddleware
21
18
  from fastapi.responses import UJSONResponse
22
19
  from pydantic import BaseModel
23
20
 
24
- from .log import get_logger
25
21
  from .repeat import repeat_every
26
- from .route import schedule_route, workflow_route
27
22
 
28
- logger = get_logger(__name__)
23
+ load_dotenv()
24
+ logger = logging.getLogger(__name__)
25
+ logging.basicConfig(
26
+ level=logging.DEBUG,
27
+ format=(
28
+ "%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d, %(thread)-5d) "
29
+ "[%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)"
30
+ ),
31
+ handlers=[logging.StreamHandler()],
32
+ datefmt="%Y-%m-%d %H:%M:%S",
33
+ )
34
+
35
+
36
+ app = FastAPI()
37
+ app.add_middleware(GZipMiddleware, minimum_size=1000)
38
+ app.queue = Queue()
39
+ app.output_dict = {}
40
+ app.queue_limit = 2
29
41
 
30
42
 
43
+ @app.on_event("startup")
44
+ @repeat_every(seconds=10, logger=logger)
31
45
  def broker_upper_messages():
46
+ """Broker for receive message from the `/upper` path and change it to upper
47
+ case.
48
+ """
32
49
  for _ in range(app.queue_limit):
33
50
  try:
34
51
  obj = app.queue.get_nowait()
35
52
  app.output_dict[obj["request_id"]] = obj["text"].upper()
36
53
  logger.info(f"Upper message: {app.output_dict}")
37
- except queue.Empty:
54
+ except Empty:
38
55
  pass
39
56
 
40
57
 
41
- jobstores = {
42
- "default": MemoryJobStore(),
43
- "sqlite": SQLAlchemyJobStore(url="sqlite:///jobs-store.sqlite"),
44
- }
45
- executors = {
46
- "default": {"type": "threadpool", "max_workers": 5},
47
- "processpool": ProcessPoolExecutor(max_workers=5),
48
- }
49
- scheduler = AsyncIOScheduler(
50
- jobstores=jobstores,
51
- executors=executors,
52
- timezone="Asia/Bangkok",
53
- )
54
-
55
-
56
- @asynccontextmanager
57
- async def lifespan(_: FastAPI):
58
- scheduler.start()
59
- yield
60
- scheduler.shutdown(wait=False)
61
-
62
-
63
- app = FastAPI(lifespan=lifespan)
64
- app.add_middleware(GZipMiddleware, minimum_size=1000)
65
- app.include_router(schedule_route)
66
- app.include_router(workflow_route)
67
-
68
- app.scheduler = scheduler
69
- app.scheduler.add_job(
70
- broker_upper_messages,
71
- "interval",
72
- seconds=10,
73
- )
74
- app.queue = queue.Queue()
75
- app.output_dict = {}
76
- app.queue_limit = 2
77
-
78
-
79
- def write_pipeline(task_id: str, message=""):
80
- logger.info(f"{task_id} : {message}")
81
- time.sleep(5)
82
- logger.info(f"{task_id} : run task successfully!!!")
83
-
84
-
85
- @app.post("/schedule/{name}", response_class=UJSONResponse)
86
- async def send_schedule(name: str, background_tasks: BackgroundTasks):
87
- background_tasks.add_task(
88
- write_pipeline,
89
- name,
90
- message=f"some message for {name}",
91
- )
92
- await fetch_current_time()
93
- return {"message": f"Schedule sent {name!r} in the background"}
94
-
95
-
96
- @repeat_every(seconds=2, max_repetitions=3)
97
- async def fetch_current_time():
98
- logger.info(f"Fetch: {datetime.now()}")
99
-
100
-
101
58
  class Payload(BaseModel):
102
59
  text: str
103
60
 
104
61
 
105
62
  async def get_result(request_id):
106
- while 1:
63
+ """Get data from output dict that global."""
64
+ while True:
107
65
  if request_id in app.output_dict:
108
66
  result = app.output_dict[request_id]
109
67
  del app.output_dict[request_id]
@@ -118,3 +76,14 @@ async def message_upper(payload: Payload):
118
76
  {"text": payload.text, "request_id": request_id},
119
77
  )
120
78
  return await get_result(request_id)
79
+
80
+
81
+ if str2bool(os.getenv("WORKFLOW_API_ENABLE_ROUTE_WORKFLOW", "true")):
82
+ from .route import workflow
83
+
84
+ app.include_router(workflow)
85
+
86
+ if str2bool(os.getenv("WORKFLOW_API_ENABLE_ROUTE_SCHEDULE", "true")):
87
+ from .route import schedule
88
+
89
+ app.include_router(schedule)
@@ -0,0 +1,51 @@
1
+ # ------------------------------------------------------------------------------
2
+ # Copyright (c) 2022 Korawich Anuttra. All rights reserved.
3
+ # Licensed under the MIT License. See LICENSE in the project root for
4
+ # license information.
5
+ # ------------------------------------------------------------------------------
6
+ from __future__ import annotations
7
+
8
+ from typing import Optional
9
+
10
+ from typer import Typer
11
+
12
+ cli: Typer = Typer()
13
+ state = {"verbose": False}
14
+
15
+
16
+ @cli.command()
17
+ def run(pipeline: str):
18
+ """Run workflow manually"""
19
+ if state["verbose"]:
20
+ print("About to create a user")
21
+
22
+ print(f"Creating user: {pipeline}")
23
+
24
+ if state["verbose"]:
25
+ print("Just created a user")
26
+
27
+
28
+ @cli.command()
29
+ def schedule(exclude: Optional[str]):
30
+ """Start workflow scheduler"""
31
+ if state["verbose"]:
32
+ print("About to delete a user")
33
+
34
+ print(f"Deleting user: {exclude}")
35
+
36
+ if state["verbose"]:
37
+ print("Just deleted a user")
38
+
39
+
40
+ @cli.callback()
41
+ def main(verbose: bool = False):
42
+ """
43
+ Manage workflow with CLI.
44
+ """
45
+ if verbose:
46
+ print("Will write verbose output")
47
+ state["verbose"] = True
48
+
49
+
50
+ if __name__ == "__main__":
51
+ cli()