#๐Ÿ”’ Asyncio with pyrogram and server tasks

96 messages ยท Page 1 of 1 (latest)

honest marshBOT
#

@unborn niche

Python help channel opened

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.

unborn niche
#

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 ๐Ÿ™‚

bright field
unborn niche
#

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

bright field
unborn niche
#

hypotetically a person can spam random commands and the server should close and open without problems

bright field
#

oi

#

!d asyncio.Lock

honest marshBOT
#

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
```...
bright field
#

this thing is specifically designed for exclusive access by tasks

bright field
#

since it's defined as async def start_server, just calling start_server() does nothing and should show a warning

unborn niche
#

crab it's true

bright field
#

uh

#

I don't remember the names anymore

unborn niche
#

the subprocess needs to be async?

bright field
#

there was something like subprocess in asyncio

unborn niche
#

it should be just one process does it really need to be async?

bright field
#

so the code always waits 45 seconds

unborn niche
#

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

bright field
#

afaik it's not necessary, since you're not doing that much IO when spawning processes, assuming you don't do it too frequently

unborn niche
#

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

unborn niche
bright field
#

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)

unborn niche
#

i don't want a sort of queue, if a person try to open it while closing the bot respond the server is occupied

unborn niche
bright field
#

and to do that, you need to keep state of what state your code tries to be in

unborn niche
#

also (obviously) in the case a person tries to close while closing that should result in the same output

unborn niche
#

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

bright field
#

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)

unborn niche
#

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

bright field
#

!pypi config

honest marshBOT
#

A hierarchical, easy-to-use, powerful configuration module for Python

Released on <t:1631347817:D>.

bright field
#

hmm

#

not entirely sure if that's related to state

unborn niche
#

me neither

#

i'll try your solution

bright field
unborn niche
#

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?

bright field
bright field
#

in command handlers you would just notify

unborn niche
#

the stop function gets kinda redirected?

unborn niche
#

i should need an asyncio course

bright field
#
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)

unborn niche
#

damn

#

seems articulated

#

there is not a simple solution like having a variable everyone can see?

bright field
#

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)

unborn niche
#

seems fine, i first need to learn more about events and conditions, as far as you show me it seems a good solution

bright field
unborn niche
#

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

honest marshBOT
#
Python help channel closed

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.