faust-streaming / faust

Python Stream Processing. A Faust fork
https://faust-streaming.github.io/faust/
Other
1.61k stars 180 forks source link

How to programmatically shutdown a faust app once a terminate message is received? #501

Closed cleomart closed 1 year ago

cleomart commented 1 year ago

Checklist

Steps to reproduce

I would like to create a on-demand kafka streaming job using faust that will get terminated once a certain message is received. Here is my code. For simplicity, I terminate the faust when a message is received.

import faust

app = faust.App("my-app",
                broker="broker:9092",
                producer_compression_type="gzip",
                broker_heartbeat_interval=30,
                broker_session_timeout=360,
                broker_request_timeout=360,
                broker_max_poll_records=1,
                topic_disable_leader=True,
                broker_max_poll_interval=3600)
topic = app.topic("test-stop")

@app.agent(topic)
async def process_messages(stream):
    async for message in stream.items():
        # Process the message
        print(message)
        await app.stop()

if __name__ == "__main__":
    app.main()

Expected behavior

I expect the faust app to be terminated gracefully and the python script would exit and the job will be completed.

Actual behavior and Full traceback

When the faust app is stopped, I get this error and the job is stuck in this infinite loop.

┌ƒaµS† v0.10.12──────────────────────────────────────────┐
│ id          │ my-app                                   │
│ transport   │ [URL('kafka://broker:9092')]             │
│ store       │ memory:                                  │
│ web         │ http://localhost:6066/                   │
│ log         │ -stderr- (info)                          │
│ pid         │ 482                                      │
│ hostname    │ supinference-54d66fc999-q2lf5            │
│ platform    │ CPython 3.7.13 (Linux x86_64)            │
│        +    │ Cython (GCC 7.5.0)                       │
│ drivers     │                                          │
│   transport │ aiokafka=0.8.0                           │
│   web       │ aiohttp=3.8.4                            │
│ datadir     │ /home/sup_inference/my-app-data          │
│ appdir      │ /home/sup_inference/my-app-data/v1       │
└─────────────┴──────────────────────────────────────────┘
[2023-05-17 23:32:04,443] [482] [INFO] [^Worker]: Starting... 
[2023-05-17 23:32:04,445] [482] [INFO] [^-App]: Starting... 
[2023-05-17 23:32:04,445] [482] [INFO] [^--Monitor]: Starting... 
[2023-05-17 23:32:04,445] [482] [INFO] [^--Producer]: Starting... 
[2023-05-17 23:32:04,445] [482] [INFO] [^---ProducerBuffer]: Starting... 
[2023-05-17 23:32:04,454] [482] [INFO] [^--CacheBackend]: Starting... 
[2023-05-17 23:32:04,454] [482] [INFO] [^--Web]: Starting... 
[2023-05-17 23:32:04,455] [482] [INFO] [^---Server]: Starting... 
[2023-05-17 23:32:04,455] [482] [INFO] [^--Consumer]: Starting... 
[2023-05-17 23:32:04,456] [482] [INFO] [^---AIOKafkaConsumerThread]: Starting... 
[2023-05-17 23:32:04,467] [482] [INFO] [^--LeaderAssignor]: Starting... 
[2023-05-17 23:32:04,467] [482] [INFO] [^--ReplyConsumer]: Starting... 
[2023-05-17 23:32:04,467] [482] [INFO] [^--AgentManager]: Starting... 
[2023-05-17 23:32:04,468] [482] [INFO] [^---Agent: __main__.process_messages]: Starting... 
[2023-05-17 23:32:04,469] [482] [INFO] [^----OneForOneSupervisor: (1@0x7fc640152290)]: Starting... 
[2023-05-17 23:32:04,469] [482] [INFO] [^---Conductor]: Starting... 
[2023-05-17 23:32:04,469] [482] [INFO] [^--TableManager]: Starting... 
[2023-05-17 23:32:04,469] [482] [INFO] [^---Conductor]: Waiting for agents to start... 
[2023-05-17 23:32:04,469] [482] [INFO] [^---Conductor]: Waiting for tables to be registered... 
[2023-05-17 23:32:05,470] [482] [INFO] [^---Recovery]: Starting... 
[2023-05-17 23:32:05,472] [482] [INFO] Updating subscribed topics to: 
┌────────────┐
│ topic name │
├────────────┤
│ test-stop  │
└────────────┘ 
[2023-05-17 23:32:05,474] [482] [INFO] Subscribed to topic(s): 
┌────────────┐
│ topic name │
├────────────┤
│ test-stop  │
└────────────┘ 
[2023-05-17 23:32:05,481] [482] [INFO] Discovered coordinator 0 for group my-app 
[2023-05-17 23:32:05,481] [482] [INFO] Revoking previously assigned partitions set() for group my-app 
[2023-05-17 23:32:05,483] [482] [INFO] (Re-)joining group my-app 
[2023-05-17 23:32:05,487] [482] [INFO] Joined group 'my-app' (generation 8) with member_id faust-0.10.12-46245648-e76e-4d90-93d9-7ef50e9b5151 
[2023-05-17 23:32:05,487] [482] [INFO] Elected group leader -- performing partition assignments using faust 
[2023-05-17 23:32:05,490] [482] [INFO] Successfully synced group my-app with generation 8 
[2023-05-17 23:32:05,490] [482] [INFO] Setting newly assigned partitions 
┌Topic Partition Set─────┐
│ topic     │ partitions │
├───────────┼────────────┤
│ test-stop │ {0-3}      │
└───────────┴────────────┘ for group my-app 
[2023-05-17 23:32:05,491] [482] [INFO] Executing _on_partitions_assigned 
[2023-05-17 23:32:05,493] [482] [INFO] generation id 8 app consumers id 8 
[2023-05-17 23:32:05,494] [482] [INFO] [^---Recovery]: Seek stream partitions to committed offsets. 
[2023-05-17 23:32:05,497] [482] [INFO] [^---Recovery]: Resuming flow... 
[2023-05-17 23:32:05,497] [482] [INFO] [^---Fetcher]: Starting... 
[2023-05-17 23:32:05,497] [482] [INFO] [^---Recovery]: Worker ready 
[2023-05-17 23:32:05,498] [482] [INFO] [^Worker]: Ready 
[2023-05-17 23:32:25,243] [482] [WARNING] (None, {'terminate': True}) 
[2023-05-17 23:32:25,244] [482] [INFO] [^-App]: Stopping... 
[2023-05-17 23:32:25,246] [482] [INFO] [^---Fetcher]: Stopping... 
[2023-05-17 23:32:25,249] [482] [INFO] [^-App]: Wait for streams... 
[2023-05-17 23:32:34,574] [482] [WARNING] [^--Consumer]: wait_empty: Waiting for tasks [(1, <ConsumerMessage: TopicPartition(topic='test-stop', partition=0) offset=0>)] 
[2023-05-17 23:32:34,582] [482] [INFO] [^--Consumer]: Agent tracebacks:

=======================================
 TRACEBACK OF ALL RUNNING AGENT ACTORS
=======================================

* sup_inference.faust_app.process_messages ----->
============================================================
['Stack for <coroutine object process_messages at 0x7fc640155950> (most recent call last):\n  File "faust_app.py", line 26, in <module>\n    app.main()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/app/base.py", line 761, in main\n    cli(app=self)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1130, in __call__\n    return self.main(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1055, in main\n    rv = self.invoke(ctx)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1657, in invoke\n    return _process_result(sub_ctx.command.invoke(sub_ctx))\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1404, in invoke\n    return ctx.invoke(self.callback, **ctx.params)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 760, in invoke\n    return __callback(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/decorators.py", line 26, in new_func\n    return f(get_current_context(), *args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 540, in _inner\n    cmd()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 621, in __call__\n    self.run_using_worker(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 631, in run_using_worker\n    raise worker.execute_from_commandline()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/mode/worker.py", line 279, in execute_from_commandline\n    self.loop.run_until_complete(self._starting_fut)\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete\n    self.run_forever()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 541, in run_forever\n    self._run_once()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once\n    handle._run()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/events.py", line 88, in _run\n    self._context.run(self._callback, *self._args)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/agents/agent.py", line 674, in _execute_actor\n    await coro\n  File "faust_app.py", line 20, in process_messages\n    await app.stop()\n']

-eof tracebacks- :-)

[2023-05-17 23:32:44,955] [482] [WARNING] [^--Consumer]: wait_empty: Waiting for tasks [(1, <ConsumerMessage: TopicPartition(topic='test-stop', partition=0) offset=0>)] 
[2023-05-17 23:32:44,957] [482] [INFO] [^--Consumer]: Agent tracebacks:

=======================================
 TRACEBACK OF ALL RUNNING AGENT ACTORS
=======================================

* sup_inference.faust_app.process_messages ----->
============================================================
['Stack for <coroutine object process_messages at 0x7fc640155950> (most recent call last):\n  File "faust_app.py", line 26, in <module>\n    app.main()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/app/base.py", line 761, in main\n    cli(app=self)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1130, in __call__\n    return self.main(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1055, in main\n    rv = self.invoke(ctx)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1657, in invoke\n    return _process_result(sub_ctx.command.invoke(sub_ctx))\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1404, in invoke\n    return ctx.invoke(self.callback, **ctx.params)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 760, in invoke\n    return __callback(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/decorators.py", line 26, in new_func\n    return f(get_current_context(), *args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 540, in _inner\n    cmd()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 621, in __call__\n    self.run_using_worker(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 631, in run_using_worker\n    raise worker.execute_from_commandline()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/mode/worker.py", line 279, in execute_from_commandline\n    self.loop.run_until_complete(self._starting_fut)\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete\n    self.run_forever()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 541, in run_forever\n    self._run_once()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once\n    handle._run()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/events.py", line 88, in _run\n    self._context.run(self._callback, *self._args)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/agents/agent.py", line 674, in _execute_actor\n    await coro\n  File "faust_app.py", line 20, in process_messages\n    await app.stop()\n']

-eof tracebacks- :-)

[2023-05-17 23:32:55,338] [482] [WARNING] [^--Consumer]: wait_empty: Waiting for tasks [(1, <ConsumerMessage: TopicPartition(topic='test-stop', partition=0) offset=0>)] 
[2023-05-17 23:32:55,339] [482] [INFO] [^--Consumer]: Agent tracebacks:

=======================================
 TRACEBACK OF ALL RUNNING AGENT ACTORS
=======================================

* sup_inference.faust_app.process_messages ----->
============================================================
['Stack for <coroutine object process_messages at 0x7fc640155950> (most recent call last):\n  File "faust_app.py", line 26, in <module>\n    app.main()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/app/base.py", line 761, in main\n    cli(app=self)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1130, in __call__\n    return self.main(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1055, in main\n    rv = self.invoke(ctx)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1657, in invoke\n    return _process_result(sub_ctx.command.invoke(sub_ctx))\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1404, in invoke\n    return ctx.invoke(self.callback, **ctx.params)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 760, in invoke\n    return __callback(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/decorators.py", line 26, in new_func\n    return f(get_current_context(), *args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 540, in _inner\n    cmd()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 621, in __call__\n    self.run_using_worker(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 631, in run_using_worker\n    raise worker.execute_from_commandline()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/mode/worker.py", line 279, in execute_from_commandline\n    self.loop.run_until_complete(self._starting_fut)\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete\n    self.run_forever()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 541, in run_forever\n    self._run_once()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once\n    handle._run()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/events.py", line 88, in _run\n    self._context.run(self._callback, *self._args)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/agents/agent.py", line 674, in _execute_actor\n    await coro\n  File "faust_app.py", line 20, in process_messages\n    await app.stop()\n']

-eof tracebacks- :-)

[2023-05-17 23:33:05,655] [482] [WARNING] [^--Consumer]: wait_empty: Waiting for tasks [(1, <ConsumerMessage: TopicPartition(topic='test-stop', partition=0) offset=0>)] 
[2023-05-17 23:33:05,656] [482] [INFO] [^--Consumer]: Agent tracebacks:

=======================================
 TRACEBACK OF ALL RUNNING AGENT ACTORS
=======================================

* sup_inference.faust_app.process_messages ----->
============================================================
['Stack for <coroutine object process_messages at 0x7fc640155950> (most recent call last):\n  File "faust_app.py", line 26, in <module>\n    app.main()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/app/base.py", line 761, in main\n    cli(app=self)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1130, in __call__\n    return self.main(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1055, in main\n    rv = self.invoke(ctx)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1657, in invoke\n    return _process_result(sub_ctx.command.invoke(sub_ctx))\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1404, in invoke\n    return ctx.invoke(self.callback, **ctx.params)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 760, in invoke\n    return __callback(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/decorators.py", line 26, in new_func\n    return f(get_current_context(), *args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 540, in _inner\n    cmd()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 621, in __call__\n    self.run_using_worker(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 631, in run_using_worker\n    raise worker.execute_from_commandline()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/mode/worker.py", line 279, in execute_from_commandline\n    self.loop.run_until_complete(self._starting_fut)\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete\n    self.run_forever()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 541, in run_forever\n    self._run_once()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once\n    handle._run()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/events.py", line 88, in _run\n    self._context.run(self._callback, *self._args)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/agents/agent.py", line 674, in _execute_actor\n    await coro\n  File "faust_app.py", line 20, in process_messages\n    await app.stop()\n']

-eof tracebacks- :-)

[2023-05-17 23:33:15,980] [482] [WARNING] [^--Consumer]: wait_empty: Waiting for tasks [(1, <ConsumerMessage: TopicPartition(topic='test-stop', partition=0) offset=0>)] 
[2023-05-17 23:33:15,982] [482] [INFO] [^--Consumer]: Agent tracebacks:

=======================================
 TRACEBACK OF ALL RUNNING AGENT ACTORS
=======================================

* sup_inference.faust_app.process_messages ----->
============================================================
['Stack for <coroutine object process_messages at 0x7fc640155950> (most recent call last):\n  File "faust_app.py", line 26, in <module>\n    app.main()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/app/base.py", line 761, in main\n    cli(app=self)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1130, in __call__\n    return self.main(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1055, in main\n    rv = self.invoke(ctx)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1657, in invoke\n    return _process_result(sub_ctx.command.invoke(sub_ctx))\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 1404, in invoke\n    return ctx.invoke(self.callback, **ctx.params)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/core.py", line 760, in invoke\n    return __callback(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/click/decorators.py", line 26, in new_func\n    return f(get_current_context(), *args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 540, in _inner\n    cmd()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 621, in __call__\n    self.run_using_worker(*args, **kwargs)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/cli/base.py", line 631, in run_using_worker\n    raise worker.execute_from_commandline()\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/mode/worker.py", line 279, in execute_from_commandline\n    self.loop.run_until_complete(self._starting_fut)\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete\n    self.run_forever()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 541, in run_forever\n    self._run_once()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once\n    handle._run()\n  File "/opt/conda/envs/sup/lib/python3.7/asyncio/events.py", line 88, in _run\n    self._context.run(self._callback, *self._args)\n  File "/opt/conda/envs/sup/lib/python3.7/site-packages/faust/agents/agent.py", line 674, in _execute_actor\n    await coro\n  File "faust_app.py", line 20, in process_messages\n    await app.stop()\n']

Versions

wbarnha commented 1 year ago

Interesting idea, never thought about something like this. There's a feature in faust called app.crash, I don't generally recommend it, but it should be interesting for your use-case. I just tested this without issues:

import faust

app = faust.App("my-app",
                broker="localhost:9092",
                broker_heartbeat_interval=30,
                broker_session_timeout=360,
                broker_request_timeout=360,
                broker_max_poll_records=1,
                topic_disable_leader=True,
                broker_max_poll_interval=3600)
topic = app.topic("test-stop", value_serializer="raw")

@app.agent(topic)
async def process_messages(stream):
    async for message in stream.items():
        await app.crash(reason=Exception("Shutdown signal received on stop topic"))

if __name__ == "__main__":
    app.main()

There's probably a more graceful way of shutting things down, but calling app.crash guarantees a shutdown.

cleomart commented 1 year ago

@wbarnha Can you please elaborate on why you do not recommend using app.crash? Any potential pitfalls when using app.crash method?

wbarnha commented 1 year ago

After running a few tests, for your use case, it seems harmless. My main concern was a consumer service gets stopped or killed too quickly and the Kafka broker wouldn't be able to gracefully coordinate the consumer exiting. But it seems that's not true at all, so app.crash() should work fine in your case.

wbarnha commented 1 year ago
import faust

app = faust.App("my-app",
                broker="localhost:9092",
                broker_heartbeat_interval=30,
                broker_session_timeout=360,
                broker_request_timeout=360,
                broker_max_poll_records=1,
                topic_disable_leader=True,
                broker_max_poll_interval=3600)
topic = app.topic("test-stop", value_serializer="raw")

@app.agent(topic)
async def process_messages(stream):
    async for message in stream.items():
        break
    await app.stop()
    app.loop.stop()

if __name__ == "__main__":
    app.main()

Gave it another crack at using app.stop() so we can assume all services get gracefully terminated.

cleomart commented 1 year ago
import faust

app = faust.App("my-app",
                broker="localhost:9092",
                broker_heartbeat_interval=30,
                broker_session_timeout=360,
                broker_request_timeout=360,
                broker_max_poll_records=1,
                topic_disable_leader=True,
                broker_max_poll_interval=3600)
topic = app.topic("test-stop", value_serializer="raw")

@app.agent(topic)
async def process_messages(stream):
    async for message in stream.items():
        break
    await app.stop()
    app.loop.stop()

if __name__ == "__main__":
    app.main()

Gave it another crack at using app.stop() so we can assume all services get gracefully terminated.

When I tried this , I am getting another error:

`[2023-05-18 19:16:15,650] [7033] [INFO] [^--CacheBackend]: Stopping...

[2023-05-18 19:16:15,652] [7033] [ERROR] [^Worker]: Error: RuntimeError('Event loop stopped before Future completed.',) Traceback (most recent call last): File "/opt/conda/envs/index_launcher/lib/python3.6/site-packages/mode/worker.py", line 273, in execute_from_commandline self.loop.run_until_complete(self._starting_fut) File "/opt/conda/envs/index_launcher/lib/python3.6/asyncio/base_events.py", line 482, in run_until_complete raise RuntimeError('Event loop stopped before Future completed.') RuntimeError: Event loop stopped before Future completed.

[2023-05-18 19:16:15,654] [7033] [INFO] [^Worker]: Gathering service tasks... [2023-05-18 19:16:15,654] [7033] [INFO] [^Worker]: Gathering all futures... [2023-05-18 19:16:17,662] [7033] [INFO] [^Worker]: Closing event loop ` and the script python returns an exit code of 1. Is this the expected behavior? If the app was shutdown gracefully, I expect no errors, and the exit code would be 0.