#๐ Asyncio with pyrogram and server tasks
96 messages ยท Page 1 of 1 (latest)
@unborn niche
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
i made a really nice description... why he deleted it
so i'm creating a script that control a telegram bot and a minecraft server, the main problem is that i want a variable to switch to know when the server is processing (opening/closing) to avoid people opening it and closing it while it's doing stuff
the current implementation uses a global boolean variable 'processing' that if set to true stop the action of closing/opening the server via commands like /startServer /stopServer
as the community said that's a bad implementation how can i improve it?
oh also the main language is Italian.... because the users are gonna be my italian friends but the code is done entirely in english even comments ๐
when another command is running, do you want newer commands to wait for that to complete or fail instantly?
nope it needs to be async, more than one people should connect and send messages
so even the same person can begin start procedure to the server hypotetically and spam /stopServer
and the server should be capable to handle this smoothly, it already does but the global thing they said it's not good
this also seems to be missing awaits on start_server and stop_server
hypotetically a person can spam random commands and the server should close and open without problems
class asyncio.Lock```
Implements a mutex lock for asyncio tasks. Not thread\-safe.
An asyncio lock can be used to guarantee exclusive access to a shared resource.
The preferred way to use a Lock is an [`async with`](https://docs.python.org/3/reference/compound_stmts.html#async-with) statement:
```py
lock = asyncio.Lock()
# ... later
async with lock:
# access shared state
```...
this thing is specifically designed for exclusive access by tasks
what type of awaits
since it's defined as async def start_server, just calling start_server() does nothing and should show a warning
crab it's true
i'm now implementing asyncio
the subprocess needs to be async?
there was something like subprocess in asyncio
it should be just one process does it really need to be async?
currently you don't have a way to wait for when exactly the process stops
so the code always waits 45 seconds
i'm overextimating times
yup
that's fine
for my case
either i need to read the process console and search for DONE elapsed time and bla bla bla
afaik it's not necessary, since you're not doing that much IO when spawning processes, assuming you don't do it too frequently
yup
that's what i was intending
i'm using io just to stop the server
and that's fine because the stop function kinda locks the server until it's done computing
so that's the only optimization i can insert?
actually reading through docs, seems like it doesn't really fit your usecase
since it only allows to wait for the lock
not to try locking it
if you want to do modelling the state of the server "the right way", one of the options is to use a state machine (if you're familiar with those)
i don't want a sort of queue, if a person try to open it while closing the bot respond the server is occupied
what is
if i queue and a person spams open close open close the server just performs useless tasks
it might be better for the command to respond with why exactly the command failed;
e.g. "server is already starting", "server is already stopping"
and to do that, you need to keep state of what state your code tries to be in
also (obviously) in the case a person tries to close while closing that should result in the same output
then i should use some sort of enumerations
a boolean should be fine
it's not a professional server
just to have fun with my friends and don't run the server 24/7 without peoples inside
so a possible architecture could be this:
store two possible states for what the user wants: "users wants the server running" and "user wants the server stopped",
when the user issues a request, notify a condition variable (https://docs.python.org/3/library/asyncio-sync.html#condition),
have one task that waits on that condition variable and has the process variable as a local variable (and is thus responsible for making sure the process state matches the desired state)
seems complicated but i'll try
i was thinking about something like import config
i just googled this issue and found this
idk anything about config
but it seems quite easy
!pypi config
something like
async with cond:
while True:
await cond.wait()
if should_run: # modified elsewhere
process = await start_process()
while should_run:
await cond.wait()
await stop_process(process)
but i think there is a simpler solution for sure
An asyncio condition primitive can be used by a task to wait for some event to happen and then get exclusive access to a shared resource.
In essence, a Condition object combines the functionality of an Event and a Lock.
so if a person spams start stop start stop it queues it?
or you can just use a plain Event
not really
in command handlers you would just notify
the stop function gets kinda redirected?
idk what this is too
i should need an asyncio course
async def startServer(app, message)
async with cond: # optional, not actually necessary
if should_start:
await message.reply("already starting")
else:
should_start = True
cond.notify() # this just wakes up the process task
, but this way you lose track of when to reply back to the user about the server having been started
(so that's a separate problem to solve)
damn
seems articulated
there is not a simple solution like having a variable everyone can see?
should_start kind of is that variable
cond is there just to tell the task "look at this value"
with just plain Event you would have something like
while True:
await event.wait()
if should_run: # modified elsewhere
process = await start_process()
while should_run:
await event.wait()
await stop_process(process)
async def startServer(app, message)
if should_start:
await message.reply("already starting")
else:
should_start = True
event.notify()
a bit simpler
because there is no locking of should_start, which is unnecessary since all its modifications are atomic (in asyncio you don't get a race condition from just writing to a variable synchronously)
seems fine, i first need to learn more about events and conditions, as far as you show me it seems a good solution
and you can also add an extra variable to keep track of whether the server is actually started
(for better error responses and for adding, for example, /serverStatus command)
seems nice
thank you very mutch for the help
i'll save your code and the references of the docs
to learn about it and implement
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.