Skip to content

Commit 5452ecb

Browse files
authored
Merge pull request #7 from Nieuwe-Warmte-Nu/6-allow-resource-init-and-cleanup
6 allow resource init and cleanup
2 parents 5289f23 + eea125d commit 5452ecb

File tree

4 files changed

+126
-106
lines changed

4 files changed

+126
-106
lines changed

README.md

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,38 +49,42 @@ rabbitmq_config = RabbitmqConfig(
4949
"5678",
5050
)
5151
nwn_client = NwnClient(postgres_config, rabbitmq_config)
52-
job_id1: uuid4 = nwn_client.start_work_flow(
53-
WorkFlowType.GROWTH_OPTIMIZER, "test_job1", "esdl_string", "test_user1", "test_proj"
54-
)
55-
job_id2: uuid4 = nwn_client.start_work_flow(
56-
WorkFlowType.GROWTH_OPTIMIZER, "test_job2", "esdl_string", "test_user2", "test_proj"
57-
)
58-
print(job_id1)
59-
60-
job1_input_esdl = nwn_client.get_job_input_esdl(job_id1)
61-
print(f"===== job1 input ESDL: {job1_input_esdl}")
62-
63-
job1_status = nwn_client.get_job_status(job_id1)
64-
print(f"===== job1 status: {job1_status}")
65-
66-
job1 = nwn_client.get_job_details(job_id1)
67-
print(f"===== {job1.job_name} input esdl: {job1.input_esdl}")
68-
69-
jobs_all = nwn_client.get_all_jobs()
70-
print(f"===== {jobs_all[1].job_name} added at: {jobs_all[1].added_at}")
71-
72-
73-
jobs_from_ids = nwn_client.get_jobs_from_ids([job_id1, job_id2])
74-
print(f"===== {jobs_from_ids[1].job_name} added at: {jobs_from_ids[1].added_at}")
75-
76-
77-
jobs_from_user = nwn_client.get_jobs_from_user("test_user1")
78-
print(f"===== Jobs from test_user1 added at: {','.join([str(job.added_at) for job in jobs_from_user])}")
79-
80-
81-
jobs_from_project = nwn_client.get_jobs_from_project("test_proj")
82-
print(f"===== Jobs from test_proj added at: {','.join([str(job.added_at) for job in jobs_from_project])}")
83-
84-
print(f"===== Deleted job with id '{job_id1}': {nwn_client.delete_job(job_id1)}")
52+
try:
53+
nwn_client.connect()
54+
job_id1: uuid4 = nwn_client.start_work_flow(
55+
WorkFlowType.GROWTH_OPTIMIZER, "test_job1", "esdl_string", "test_user1", "test_proj"
56+
)
57+
job_id2: uuid4 = nwn_client.start_work_flow(
58+
WorkFlowType.GROWTH_OPTIMIZER, "test_job2", "esdl_string", "test_user2", "test_proj"
59+
)
60+
print(job_id1)
61+
62+
job1_input_esdl = nwn_client.get_job_input_esdl(job_id1)
63+
print(f"===== job1 input ESDL: {job1_input_esdl}")
64+
65+
job1_status = nwn_client.get_job_status(job_id1)
66+
print(f"===== job1 status: {job1_status}")
67+
68+
job1 = nwn_client.get_job_details(job_id1)
69+
print(f"===== {job1.job_name} input esdl: {job1.input_esdl}")
70+
71+
jobs_all = nwn_client.get_all_jobs()
72+
print(f"===== {jobs_all[1].job_name} added at: {jobs_all[1].added_at}")
73+
74+
75+
jobs_from_ids = nwn_client.get_jobs_from_ids([job_id1, job_id2])
76+
print(f"===== {jobs_from_ids[1].job_name} added at: {jobs_from_ids[1].added_at}")
77+
78+
79+
jobs_from_user = nwn_client.get_jobs_from_user("test_user1")
80+
print(f"===== Jobs from test_user1 added at: {','.join([str(job.added_at) for job in jobs_from_user])}")
81+
82+
83+
jobs_from_project = nwn_client.get_jobs_from_project("test_proj")
84+
print(f"===== Jobs from test_proj added at: {','.join([str(job.added_at) for job in jobs_from_project])}")
85+
86+
print(f"===== Deleted job with id '{job_id1}': {nwn_client.delete_job(job_id1)}")
87+
finally:
88+
nwn_client.stop()
8589

8690
```

src/nwnsdk/nwn_client.py

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from dataclasses import dataclass
2-
from typing import List
2+
from typing import List, Callable, Dict
33
from uuid import uuid4
44

55
from nwnsdk.postgres.dbmodels import Job
6-
from nwnsdk.rabbitmq.rabbitmq_client import RabbitmqClient
6+
from nwnsdk.rabbitmq.rabbitmq_client import RabbitmqClient, Queue, PikaCallback
77

88
import logging
99
from nwnsdk.postgres.postgres_client import PostgresClient
@@ -12,65 +12,45 @@
1212
LOGGER = logging.getLogger("nwnsdk")
1313

1414

15-
class NwnClient:
15+
class NwnClient(PostgresClient, RabbitmqClient):
1616
rabbitmq_client: RabbitmqClient
1717
postgres_client: PostgresClient
1818
logger: logging.Logger
1919

2020
def __init__(self, postgres_config: PostgresConfig, rabbitmq_config: RabbitmqConfig):
21-
self.rabbitmq_client = RabbitmqClient(rabbitmq_config)
22-
self.postgres_client = PostgresClient(postgres_config)
21+
PostgresClient.__init__(self, postgres_config)
22+
RabbitmqClient.__init__(self, rabbitmq_config)
23+
24+
def connect(self):
25+
PostgresClient._connect_postgres(self)
26+
RabbitmqClient._connect_rabbitmq(self)
27+
28+
def stop(self):
29+
PostgresClient._close_postgres(self)
30+
RabbitmqClient._stop_rabbitmq(self)
2331

2432
def start_work_flow(
25-
self, work_flow_type: WorkFlowType, job_name: str, esdl_str: str, user_name: str, project_name: str
33+
self, work_flow_type: WorkFlowType, job_name: str, esdl_str: str, user_name: str, project_name: str
2634
) -> uuid4:
2735
job_id: uuid4 = uuid4()
28-
self.postgres_client.send_input(
36+
PostgresClient._send_input(
37+
self,
2938
job_id=job_id,
3039
job_name=job_name,
3140
work_flow_type=work_flow_type,
3241
esdl_str=esdl_str,
3342
user_name=user_name,
3443
project_name=project_name,
3544
)
36-
self.rabbitmq_client.send_start_work_flow(job_id, work_flow_type)
45+
RabbitmqClient._send_start_work_flow(self, job_id, work_flow_type)
3746

3847
return job_id
3948

40-
def get_job_status(self, job_id: uuid4) -> JobStatus:
41-
return self.postgres_client.get_job_status(job_id)
42-
43-
def get_job_input_esdl(self, job_id: uuid4) -> str:
44-
return self.postgres_client.get_job_input_esdl(job_id)
45-
46-
def get_job_output_esdl(self, job_id: uuid4) -> str:
47-
return self.postgres_client.get_job_output_esdl(job_id)
48-
49-
def get_job_logs(self, job_id: uuid4) -> str:
50-
return self.postgres_client.get_job_logs(job_id)
51-
5249
def get_job_details(self, job_id: uuid4) -> Job:
53-
return self.postgres_client.get_job(job_id)
50+
return self.get_job(job_id)
5451

5552
def get_all_jobs(self) -> List[Job]:
56-
return self.postgres_client.get_jobs()
53+
return self.get_jobs()
5754

5855
def get_jobs_from_ids(self, job_ids: List[uuid4]) -> List[Job]:
59-
return self.postgres_client.get_jobs(job_ids)
60-
61-
def get_jobs_from_user(self, user_name: str) -> List[Job]:
62-
return self.postgres_client.get_jobs_from_user(user_name)
63-
64-
def get_jobs_from_project(self, project_name: str) -> List[Job]:
65-
return self.postgres_client.get_jobs_from_project(project_name)
66-
67-
def delete_job(self, job_id: uuid4) -> bool:
68-
return self.postgres_client.delete_job(job_id)
69-
70-
@property
71-
def db_client(self) -> PostgresClient:
72-
return self.postgres_client
73-
74-
@property
75-
def broker_client(self) -> RabbitmqClient:
76-
return self.rabbitmq_client
56+
return self.get_jobs(job_ids)

src/nwnsdk/postgres/postgres_client.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sqlalchemy import select, update, delete
77
from sqlalchemy.orm import Session
88
from sqlalchemy.orm.strategy_options import load_only
9+
from sqlalchemy.engine import Engine
910

1011
from nwnsdk import PostgresConfig, WorkFlowType
1112
from nwnsdk.postgres.database import initialize_db, session_scope
@@ -29,17 +30,27 @@
2930

3031

3132
class PostgresClient:
33+
db_config: PostgresConfig
34+
engine: Engine
35+
3236
def __init__(self, postgres_config: PostgresConfig):
33-
initialize_db("nwn", postgres_config)
34-
35-
def send_input(
36-
self,
37-
job_id: uuid4,
38-
job_name: str,
39-
work_flow_type: WorkFlowType,
40-
esdl_str: str,
41-
user_name: str,
42-
project_name: str,
37+
self.db_config = postgres_config
38+
39+
def _connect_postgres(self):
40+
self.engine = initialize_db("nwn", self.db_config)
41+
42+
def _close_postgres(self):
43+
if self.engine:
44+
self.engine.dispose()
45+
46+
def _send_input(
47+
self,
48+
job_id: uuid4,
49+
job_name: str,
50+
work_flow_type: WorkFlowType,
51+
esdl_str: str,
52+
user_name: str,
53+
project_name: str,
4354
) -> None:
4455
with session_scope() as session:
4556
new_job = Job(

src/nwnsdk/rabbitmq/rabbitmq_client.py

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import logging
44
from enum import Enum
5-
import signal
65
from typing import Callable, Dict
76
from uuid import uuid4
87

98
import pika
9+
import pika.exceptions
1010
import json
1111

1212
from pika.adapters.blocking_connection import BlockingChannel
@@ -33,49 +33,74 @@ def from_workflow_type(workflow_type: WorkFlowType) -> "Queue":
3333

3434

3535
class RabbitmqClient:
36+
rabbitmq_is_running: bool
37+
rabbitmq_config: RabbitmqConfig
3638
rabbitmq_exchange: str
39+
connection: pika.BlockingConnection
3740
channel: BlockingChannel
3841
queue: str
3942

4043
def __init__(self, config: RabbitmqConfig):
44+
self.rabbitmq_is_running = False
45+
self.rabbitmq_config = config
4146
self.rabbitmq_exchange = config.exchange_name
4247

48+
def _connect_rabbitmq(self):
4349
# initialize rabbitmq connection
44-
LOGGER.info("Connecting to RabbitMQ at %s:%s as user %s", config.host, config.port, config.user_name)
45-
credentials = pika.PlainCredentials(config.user_name, config.password)
50+
LOGGER.info(
51+
"Connecting to RabbitMQ at %s:%s as user %s",
52+
self.rabbitmq_config.host,
53+
self.rabbitmq_config.port,
54+
self.rabbitmq_config.user_name,
55+
)
56+
credentials = pika.PlainCredentials(self.rabbitmq_config.user_name, self.rabbitmq_config.password)
4657
parameters = pika.ConnectionParameters(
47-
config.host, config.port, "/", credentials, heartbeat=3600, blocked_connection_timeout=3600
58+
self.rabbitmq_config.host,
59+
self.rabbitmq_config.port,
60+
"/",
61+
credentials,
62+
heartbeat=3600,
63+
blocked_connection_timeout=3600,
64+
connection_attempts=10,
4865
)
4966

50-
connection = pika.BlockingConnection(parameters)
67+
self.connection = pika.BlockingConnection(parameters)
5168

52-
self.channel = connection.channel()
69+
self.channel = self.connection.channel()
5370
self.channel.basic_qos(prefetch_size=0, prefetch_count=1)
5471
self.channel.exchange_declare(exchange=self.rabbitmq_exchange, exchange_type="topic")
5572
self.queue = self.channel.queue_declare(Queue.StartWorkflowOptimizer.value, exclusive=False).method.queue
5673
self.channel.queue_bind(self.queue, self.rabbitmq_exchange, routing_key=Queue.StartWorkflowOptimizer.value)
5774
LOGGER.info("Connected to RabbitMQ")
5875

59-
def wait_for_data(self, callbacks: Dict[Queue, PikaCallback]):
60-
for queue, callback in callbacks.items():
61-
self.channel.basic_consume(queue=queue.value, on_message_callback=callback, auto_ack=False)
62-
63-
def stop(signal, frame):
64-
LOGGER.info("Received signal %s. Stopping..", signal)
65-
self.channel.stop_consuming()
66-
67-
signal.signal(signal.SIGINT, stop)
68-
signal.signal(signal.SIGTERM, stop)
69-
70-
LOGGER.info("Waiting for input...")
71-
self.channel.start_consuming()
72-
73-
def send_start_work_flow(self, job_id: uuid4, work_flow_type: WorkFlowType):
76+
def wait_for_work(self, callbacks: Dict[Queue, PikaCallback]):
77+
self.rabbitmq_is_running = True
78+
79+
while self.rabbitmq_is_running:
80+
try:
81+
for queue, callback in callbacks.items():
82+
self.channel.basic_consume(queue=queue.value, on_message_callback=callback, auto_ack=False)
83+
LOGGER.info("Waiting for input...")
84+
self.channel.start_consuming()
85+
except pika.exceptions.ConnectionClosedByBroker as exc:
86+
LOGGER.info('Connection was closed by broker. Reason: "%s". Shutting down...', exc.reply_text)
87+
except pika.exceptions.AMQPConnectionError:
88+
LOGGER.info("Connection was lost, retrying...")
89+
self._connect_rabbitmq()
90+
91+
def _send_start_work_flow(self, job_id: uuid4, work_flow_type: WorkFlowType):
7492
# TODO convert to protobuf
7593
# TODO job_id converted to string for json
7694
body = json.dumps({"job_id": str(job_id)})
77-
self.send_output(Queue.from_workflow_type(work_flow_type), body)
95+
self._send_output(Queue.from_workflow_type(work_flow_type), body)
7896

79-
def send_output(self, queue: Queue, message: str):
97+
def _send_output(self, queue: Queue, message: str):
8098
body: bytes = message.encode("utf-8")
8199
self.channel.basic_publish(exchange=self.rabbitmq_exchange, routing_key=queue.value, body=body)
100+
101+
def _stop_rabbitmq(self):
102+
self.rabbitmq_is_running = False
103+
if self.channel:
104+
self.channel.stop_consuming()
105+
if self.connection:
106+
self.connection.close()

0 commit comments

Comments
 (0)