Async usage

Hello,

I’m trying to use Telegram API with asyncronous programming. My program basically validates logs for specifeid arguments.

My first attempt was:

using Telegram, Random

# validation is IO bound log checking
function validate1(name) 
    sleep(1) 
    rand() < 0.9
end

function validate2(name) 
    sleep(1) 
    rand() < 0.8
end

action_telegram(name) = Telegram.API.sendMessage(text="$name")
action2(name) = sleep(10) # long IO bound action

function validate(name)
    # this list will have many pairs
    fs = [validate1 => action_telegram, validate2 => action2]
    for (f, action) ∈ fs
        if f(name)
            println("$(nameof(f)) -> $(nameof(action))")
            action(name)
            return
        end
    end
end

function test1()
    tg = TelegramClient("", chat_id = "")
    names = repeat(["test"], 20)
    @sync for name ∈ names
        @async validate(name)
    end
end

This would be perfect, but I get “Too many request” from Telegram servers, so ideally I would like to group all messages in one.

I did this workaround:

function validate_alt(name)
    fs = [validate1 => action_telegram, validate2 => action2]
    for (f, action) ∈ fs
        if f(name)
            println("$(nameof(f)) -> $(nameof(action))")
            if nameof(action) == :action_telegram
                return true
            else
                action(name)
            end
        end
    end
    return false
end


function test2()
    tg = TelegramClient("", chat_id = "")
    names = repeat(["test"], 20)
    mask = zeros(Bool, length(names))
    @sync for (i, name) ∈ enumerate(names)
        @async mask[i] = validate_alt(name)
    end
    action_telegram(join(names[mask], "\n"))
    return
end

But this is rather inconvenient since in my real code I have many “action” and “validation” functions, so this workaround looks out of place.

I would be greateful for any suggestions for more elegant solution. I don’t mind restructuring my code.

You can use producer/consumers pattern. Just make a Channel which will hold commands, and fill it with producer. On the other side of this channel run as many consumers as telegram allows, take! messages and send them. This is pretty standard tactic.

Some relevant information:
https://docs.julialang.org/en/v1/manual/asynchronous-programming/#More-on-Channels

1 Like

Thanks, Channel was a perfect fit, got it working nicely.