Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduled callable events #1222

Closed
deathbybandaid opened this issue Sep 15, 2017 · 14 comments
Closed

Scheduled callable events #1222

deathbybandaid opened this issue Sep 15, 2017 · 14 comments
Labels
Declined Requests that will not be implemented for technical or project direction reasons Feature

Comments

@deathbybandaid
Copy link
Contributor

deathbybandaid commented Sep 15, 2017

Hi, not really an issue, but I wanted to know if the functionality existed and how to use it.

I have an event that is at 7pm daily, I want sopel to announce it to the channel.

I also want sopel to check an rss feed for updates at regular intervals, and if there is new content, to announce it to the channel.

I see there is something called "jobs", but I'm not sure how to add "jobs"

Thanks!

@kwaaak
Copy link
Contributor

kwaaak commented Sep 15, 2017

https://github.com/RebelCodeBase/sopel-rss

Try .help at and .help in for your other question

@deathbybandaid
Copy link
Contributor Author

deathbybandaid commented Sep 26, 2017

I looked at .help in and .help at

I'm not looking for something that I call from within IRC, but directly in the module.

I found a workaround, but I feel like there should be a better way:

import sopel.module
import datetime

# scheduled event is at 23:00 UTC daily
@sopel.module.interval(60)
def scheduledevent(bot):
    for channel in bot.channels:
        now = datetime.datetime.utcnow()
        if now.hour == 23 and now.minute == 10:
            bot.msg(channel, "This is the scheduled event")

I feel like what Sopel needs is something along the lines of:

import sopel.module

@sopel.module.schedule(23,10)
def scheduledevent(bot):
    for channel in bot.channels:
        bot.msg(channel, "This is the scheduled event")

@dgw dgw changed the title Timed events Scheduled callable events Mar 25, 2018
@SpiceBot
Copy link

Additional Ideas:

Idea 1, optionally pass timezone along with it.

@sopel.module.schedule(23,10, timezone=UTC)

Wouldn't be often needed, but I could see it coming in handy.

Idea 2

I have some stuff that I like to run when the bot is starting. Right now, I use a poor method:
(The nines are there in an attempt to not actually run every 5 seconds)


startupinterval = 5

# Startup check
@sopel.module.interval(startupinterval )
def startupcheck(bot):

    if "startup_op_check" in bot.memory:
        startupinterval += 999999999999999999
        return
    bot.memory["startup_op_check"] = True
    
    startupinterval += 999999999999999999

    """ Run The Code """

What I'd suggest is something more like:

@sopel.module.startup()
def startupevent(bot):
    """ do the thing """

Idea 3, what I sometimes do for the bot joining a new channel

# watch Joins
@event('JOIN')
@rule('.*')
@sopel.module.thread(True)
def joindetect(bot, trigger):
    if trigger.nick == bot.nick:
        """ do the thing """

should have something like:

@sopel.module.botjoin()
def botjoinedachan(bot):
    """ do the thing """

@dgw
Copy link
Member

dgw commented Sep 26, 2018

@SpiceBot Apart from being off-topic for this issue, Idea 2 is already available if you define a method in your module called setup(bot). Idea 3 is fine I guess (though also off-topic), but I'm not particularly excited about the idea of adding special-case methods to sopel.module when they're pretty trivial to do with the existing tools.

Idea 1 goes with this discussion, though. Timezone is probably a good optional parameter, yes. Fallback can be either UTC or bot.config.core.default_timezone.

@kwaaak
Copy link
Contributor

kwaaak commented Sep 27, 2018

(The nines are there in an attempt to not actually run every 5 seconds)

Are you sure that it doesn't just run every 5 seconds anyway?
I think I tried something with a random interval time once but it never worked, it just used the interval that was defined for the first run every time.

@Exirel
Copy link
Contributor

Exirel commented May 1, 2019

As far as I'm concerned, this looks like it requires developers to write a Sopel plugin with the right usage of the sopel.module.interval decorator.

@dgw we can consider this as a feature request, but I'm more or less thinking that we should decline this, and put an emphasis on documentation, eg. having better example of how interval can be used, and the various pattern to pull things at regular intervals without overloading the CPU.

@dgw dgw added Declined Requests that will not be implemented for technical or project direction reasons and removed Patches Welcome labels Sep 27, 2019
@dgw
Copy link
Member

dgw commented Sep 27, 2019

Basically, anything we might implement would be a wrapper around standard library functionality. It's not worth having a decorator.

Plus, as soon as we implement scheduling callables at the same time every day, someone will ask for choosing which days of the week/month/blah. Choosing multiple times. Choosing random times. All of which is pretty easily doable with stdlib tools, without any help from Sopel. 😸

@dgw dgw closed this as completed Sep 27, 2019
@dgw
Copy link
Member

dgw commented Sep 27, 2019

@deathbybandaid, since I know you're still writing tons of plugin code, I'll leave you with a third-party-library approach and one of many stdlib-based examples.

@ronilaukkarinen
Copy link

@dgw Yes, I tried couple of those but didn't get any output (yes, Timezone set to here, Europe/Helsinki). I'm not very experienced in Python so it's difficult for me to modify some raw python to sopel bot.say... Been searching for a long time an example sopel script that has timed message but have not find one yet. I'd just need bot to say something when it hits 00:00 (midnight) local time.

@dgw
Copy link
Member

dgw commented Feb 23, 2021

Probably the easiest way to do it is by installing schedule, and using that in your Sopel plugin:

import schedule
from sopel import module


def scheduled_message(bot):
    bot.say("This is the scheduled message.", "#channelname")


def setup(bot):
    # schedule the message at midnight every day
    schedule.every().day.at('00:00').do(scheduled_message, bot=bot)


@module.interval(60)
def run_schedule(bot):
    schedule.run_pending()

Note, I haven't tested this at all (not even syntax validation), but it's the general idea. You use schedule to set up the tasks and define the arguments when the plugin is loaded, and @sopel.module.interval to have Sopel ask schedule to run any pending jobs every 60 seconds. Passing arguments to schedule jobs is covered in its docs here.

Edge cases like the bot getting disconnected just as the scheduled job gets started aren't currently handled by the example code above, either. I'm very much rushing to get this typed out in between $day_job tasks. 😅

@ronilaukkarinen
Copy link

Finally gave it a go and couln't get it to work :( the message never triggers.

@ronilaukkarinen
Copy link

Tested it again and figured it out. Fixed some syntax errors. Scheduled message for midnight works like this:

def scheduled_message(bot):
    bot.say('This is the scheduled message.', '#channel')

def setup(bot):
    schedule.every().day.at('00:00').do(scheduled_message, bot=bot)

@sopel.module.interval(60)
def run_schedule(bot):
    schedule.run_pending()

Thanks!

@Exirel
Copy link
Contributor

Exirel commented May 18, 2021

Well done. :)

@dgw
Copy link
Member

dgw commented May 18, 2021

I see, I forgot a () in the long chain of methods/attributes. Good catch, and glad it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Declined Requests that will not be implemented for technical or project direction reasons Feature
Projects
None yet
Development

No branches or pull requests

5 participants