def test_handle_signals(self): with self.assertLogs("gestalt.runner", level=logging.INFO) as log: run(sigint_func) self.assertIn("Caught SIGINT", log.output[0]) with self.assertLogs("gestalt.runner", level=logging.INFO) as log: run(sigterm_func) self.assertIn("Caught SIGTERM", log.output[0])
counter += 1 request_msg = dict(sequence_number=counter, utc=True) # For demonstration purposes randomly choose to use an invalid # service name to show that the message gets returned and raises # a DeliveryError exception. service_name = (r.service_name if random.random() < 0.8 else "invalid_service_name") try: logger.info(f"Sending request {request_msg} to {service_name}") response_msg = await r.request(request_msg, expiration=2, service_name=service_name) logger.info(f"Received response: {response_msg}") except asyncio.TimeoutError as exc: logger.info(f"Request was timed-out: {exc}") except asyncio.CancelledError as exc: logger.info(f"Request was cancelled: {exc}") except DeliveryError as exc: logger.info(f"Request delivery error: {exc}") # Wait some time before sending another request await asyncio.sleep(3) async def start_requesting(r): await r.start() await asyncio.sleep(1) asyncio.get_event_loop().create_task(message_requester(r)) run(start_requesting(requester), finalize=requester.stop)
def test_pending_tasks_are_cancelled_when_stopping_loop(self): with self.assertLogs("gestalt.runner", level=logging.DEBUG) as log: run(spawn_another_task) self.assertTrue( ["Cancelling 1 pending tasks" in log_msg for log_msg in log.output] )
def test_handle_exceptions(self): with self.assertLogs("gestalt.runner", level=logging.ERROR) as log: run(exception_func) self.assertIn("Caught exception", log.output[0])
def test_exception_is_raised_if_finalize_is_not_awaitable(self): with self.assertRaises(Exception) as exc: run(valid_func, finalize=invalid_func) self.assertIn( "finalize must be a coroutine or a coroutine function", str(exc.exception) )
def test_valid_runner_func(self): run(valid_func) run(valid_func()) run(valid_func, finalize=valid_finalize) run(valid_func, finalize=valid_finalize())
now = datetime.datetime.now(tz=datetime.timezone.utc) msg = dict(timestamp=now.isoformat(), counter=1) client.send(msg, peer_id=peer_id) def on_peer_unavailable(cli: NetstringStreamClient, peer_id): print(f"Client {peer_id} connected") async def on_message(cli: NetstringStreamClient, data, peer_id, **kwargs) -> None: print(f"Client received msg from {peer_id}: {data}") # Wait briefly before sending a reply to the reply! await asyncio.sleep(1) msg_count = data["counter"] + 1 # Send a reply to the specific peer that sent the msg now = datetime.datetime.now(tz=datetime.timezone.utc) msg = dict(timestamp=now.isoformat(), counter=msg_count) client.send(msg, peer_id=peer_id) client = NetstringStreamClient( on_message=on_message, on_started=on_started, on_stopped=on_stopped, on_peer_available=on_peer_available, on_peer_unavailable=on_peer_unavailable, content_type=CONTENT_TYPE_JSON, ) run(client.start(args.host, args.port), finalize=client.stop)
from gestalt.timer import Timer from gestalt.runner import run async def timerFunction(name, **kwargs): print(f"Executing {name} timer function") async def start_demo(t1, t2, t3): await t1.start() await t2.start() await t3.start() async def stop_demo(t1, t2, t3): await t1.stop() await t2.stop() await t3.stop() if __name__ == "__main__": timer1 = Timer(0.5, timerFunction, "oneshot") timer2 = Timer(0.75, timerFunction, "thrice", repeats=3) timer3 = Timer(1.0, timerFunction, "forever", forever=True) run(start_demo(timer1, timer2, timer3), finalize=stop_demo(timer1, timer2, timer3))
print("Server has stopped") def on_peer_available(server, peer_id): print(f"Server peer {peer_id} connected") def on_peer_unavailable(server, peer_id): print(f"Server peer {peer_id} disconnected") async def on_message(server, data, peer_id, **kwargs) -> None: msg = data.decode() print(f"Server received msg from {peer_id}: {msg}") # Wait briefly before sending a reply to the reply! await asyncio.sleep(1) now = datetime.datetime.now(tz=datetime.timezone.utc) msg = now.isoformat() # Send a reply to the specific peer that sent the msg server.send(msg.encode(), peer_id=peer_id) svr = LineDelimitedStreamServer( on_message=on_message, on_started=on_started, on_stopped=on_stopped, on_peer_available=on_peer_available, on_peer_unavailable=on_peer_unavailable, content_type=CONTENT_TYPE_DATA, ) run(svr.start(args.host, args.port), finalize=svr.stop)
type=int, default=53123, help="The port that the receiver will listening on", ) parser.add_argument( "--log-level", type=str, choices=["debug", "info", "error"], default="error", help="Logging level. Default is 'error'.", ) args = parser.parse_args() logging.basicConfig( format= "%(asctime)s.%(msecs)03.0f [%(levelname)s] [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=getattr(logging, args.log_level.upper()), ) def on_message(self, data, **kwargs) -> None: addr = kwargs.get("addr") print(f"Received msg from {addr}: {data}") ep = DatagramEndpoint(on_message=on_message, content_type=CONTENT_TYPE_JSON) local_address = (args.host, args.port) run(ep.start(local_addr=local_address, reuse_port=True), finalize=ep.stop)
datefmt="%Y-%m-%d %H:%M:%S", level=numeric_level, ) producer = Producer( amqp_url=args.amqp_url, exchange_name=args.exchange_name, routing_key=args.routing_key, ) # When you parse a serialized protocol buffer message you have to know what # kind of type you're expecting. However, a serialized protocol buffer # message does not provide this identifying information. When using Protobuf # serialization the type must be registered with the serializer so that # an identifier can be associated with the type. The type identifier is # pass in a message header field. This must be done on sender and consumer # sides in the same order. # # Register messages that require using the x-type-id message attribute serializer = serialization.registry.get_serializer(CONTENT_TYPE_PROTOBUF) type_identifier = serializer.registry.register_message(Position) async def start_producing(p): await p.start() # Start producing messages loop = asyncio.get_event_loop() loop.create_task(message_producer(p)) run(start_producing(producer), finalize=producer.stop)
) ep = MtiDatagramEndpoint(content_type=CONTENT_TYPE_PROTOBUF) # Associate a message object with a unique message type identifier. type_identifier = 1 ep.register_message(type_identifier, Position) async def message_producer(e) -> None: """ Generate a new message and send it """ while True: protobuf_data = Position( latitude=130.0, longitude=-30.0, altitude=50.0, status=Position.SIMULATED, # pylint: disable=no-member ) print(f"sending a message: {protobuf_data}") e.send(protobuf_data, type_identifier=type_identifier) await asyncio.sleep(1.0) async def start_producing(e, remote_addr): await e.start(remote_addr=remote_addr) # Start producing messages loop = asyncio.get_event_loop() loop.create_task(message_producer(e)) remote_address = (args.host, args.port) run(start_producing(ep, remote_address), finalize=ep.stop)
parser.add_argument( "--log-level", type=str, choices=["debug", "info", "error"], default="error", help="Logging level. Default is 'error'.", ) args = parser.parse_args() logging.basicConfig( format= "%(asctime)s.%(msecs)03.0f [%(levelname)s] [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=getattr(logging, args.log_level.upper()), ) def on_message(self, data, **kwargs) -> None: addr = kwargs.get("addr") print(f"Received msg from {addr}: {data}") ep = MtiDatagramEndpoint(on_message=on_message, content_type=CONTENT_TYPE_PROTOBUF) # Associate a message object with a unique message type identifier. type_identifier = 1 ep.register_message(type_identifier, Position) local_address = (args.host, args.port) run(ep.start(local_addr=local_address), finalize=ep.stop)
raise Exception(f"Invalid log-level: {args.log_level}") logging.basicConfig( format= "%(asctime)s.%(msecs)03.0f [%(levelname)s] [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=numeric_level, ) consumer = Consumer( amqp_url=args.amqp_url, exchange_name=args.exchange_name, routing_key=args.routing_key, on_message=on_message_callback, ) # When you parse a serialized protocol buffer message you have to know what # kind of type you're expecting. However, a serialized protocol buffer # message does not provide this identifying information. When using Protobuf # serialization the type must be registered with the serializer so that # an identifier can be associated with the type. The type identifier is # pass in a message header field. This must be done on sender and consumer # sides in the same order. # # Register messages that require using the x-type-id message attribute serializer = serialization.registry.get_serializer( serialization.CONTENT_TYPE_PROTOBUF) type_identifier = serializer.registry.register_message(Position) run(consumer.start, finalize=consumer.stop)
logging.basicConfig( format= "%(asctime)s.%(msecs)03.0f [%(levelname)s] [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=getattr(logging, args.log_level.upper()), ) ep = DatagramEndpoint(content_type=CONTENT_TYPE_JSON) async def message_producer(e, bcast_addr) -> None: """ Generate a new message and send it """ while True: now = datetime.datetime.now(tz=datetime.timezone.utc) json_msg = dict(timestamp=now.isoformat()) print(f"sending message: {json_msg}") e.send(json_msg, addr=bcast_addr) await asyncio.sleep(1.0) async def start_producing(e, local_addr, bcast_addr): await e.start(local_addr=local_addr, allow_broadcast=True) # Start producing messages loop = asyncio.get_event_loop() loop.create_task(message_producer(e, bcast_addr)) local_address = ("0.0.0.0", 0) broadcast_address = (args.broadcast_host, args.broadcast_port) run(start_producing(ep, local_address, broadcast_address), finalize=ep.stop)