Rozon
Rozon

Reputation: 33

How do I repeat my custom function every 15 minutes? (Julia)

I was trying to write a function that would take the amount of players currently logged into oldschool runescape and append the amount with the current time and date into a csv file. This function works great, but when I try to use the Timer function to repeat the function multiple times it shows an error. (I want it to run every 15 minutes on my idle laptop indefinitely).

This is the function:

function countplayers()
    res = HTTP.get("https://oldschool.runescape.com")
    body = String(res.body);
    locatecount = findfirst("There are currently", body);
    firstplayercount = body[locatecount[end]+2:locatecount[end]+8]
    first = firstplayercount[1:findfirst(',',firstplayercount)-1]
    if findfirst(',',firstplayercount) == 3
        second = firstplayercount[findfirst(',',firstplayercount)+1:end-1]
    else
        second = firstplayercount[findfirst(',',firstplayercount)+1:end]
    end
    finalcount = string(first,second)
    currentdate = Dates.now()
    concatenated = [finalcount, currentdate]
    f = open("test.csv","a")
    write(f, finalcount,',')
    write(f, string(currentdate), '\n')
    close(f)
end

If I try Timer(countplayers(),10,10) to test it out, I get this error:

**ERROR: MethodError: no method matching Timer(::Nothing, ::Int64, ::Int64)**

The same error appears if the timer is placed below the function and if the timer command is used in the REPL. What am I doing wrong? Thanks in advance!

Upvotes: 3

Views: 617

Answers (3)

StefanKarpinski
StefanKarpinski

Reputation: 33259

The canonical way to do this is to start an async task and just run it in a loop and sleep in between:

@async while true
    my_function()
    sleep(15*60)
end

Because this block is async, evaluating this will return immediately and the task will just run in the background until the program exits.

Upvotes: 3

In addition to other answers, here is another solution, more inline with what you were trying to do:

julia> using Dates
julia> function countplayers()
           println("$(now()) There are 42 players")
       end
countplayers (generic function with 1 method)

# Run `countplayers` every 3s, starting now (delay=0)
julia> t = Timer(_->countplayers(), 0, interval=3);
2020-11-10T17:52:42.904 There are 42 players
2020-11-10T17:52:45.896 There are 42 players
2020-11-10T17:52:48.899 There are 42 players
2020-11-10T17:52:51.902 There are 42 players
2020-11-10T17:52:54.905 There are 42 players
2020-11-10T17:52:57.908 There are 42 players
2020-11-10T17:53:00.909 There are 42 players

# When you want to stop the task
julia> close(t)

Upvotes: 4

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42214

Extending on Stefan's suggestion how to start here is a full working and very useful code:

function dosomething(f, interval) 
    stopper = Ref(false)
    task = @async while !stopper[]
        f()
        sleep(interval)
    end
    return task, stopper
end

Now let us see this action:

julia> task, stopper = dosomething(()->println("Hello World"),10)
Hello World
(Task (runnable) @0x000000001675c5d0, Base.RefValue{Bool}(false))

julia> Hello World
julia>

julia> stopper[]=true;  # I do not want my background process anymore running


julia> task    #after few seconds the status will be done
Task (done) @0x000000001675c5d0

Finally, it also should be noted that in production systems usually the most robust approach is to use system tools such as crontab for controlling and managing such recurring events.

Upvotes: 4

Related Questions