Judging by the number of mods that don't use scheduled tasks in 2.0, it seems to be that there is a little bit of confusion on how to create them. So, here goes - with thanks to JBlaze for getting me started on it in the first place.
Any scheduled task requires 3 basic things: code to run, a description in the language files, and an entry in the database.
For the purpose of this, I'm actually going to talk you through a simplified version of my Auto Lock Old Topics (http://custom.simplemachines.org/mods/index.php?mod=2040) mod, where instead of locking threads configurably, we'll just say we lock every thread that hasn't been replied to in 30 days.
The very first thing we need to do is give our task an identifier. It doesn't have to be special but needs to be short and as unique as you can be. I used 'autoLock' for mine, so we'll continue to use that here to keep it straightforward.
DescriptionLet's start with the easiest thing: description. Each scheduled task has a name and a quick description, which you can see in the Scheduled Tasks part of the Admin area in 2.0. The name is also a link to configure when the script should run, and we don't want to get into modifying things we don't need to for it.
In fact, adding a description is nice and easy, you just have to add 2 lines to ManageScheduledTasks.english.php in the theme (for the budding mod authors out there, it's $languagedir/ManageScheduledTasks.english.php you want, plus any other language variations)
Here's where the identifier comes in. We create two language strings, scheduled_task_{identifier} and scheduled_task_desc_{identifier} and add them to $txt.
So to the bottom of ManageScheduledTasks.english.php, I would add:
$txt['scheduled_task_autoLock'] = 'Auto Lock Old Topics';
$txt['scheduled_task_desc_autoLock'] = 'Locks topics that have not been replied to in 30 days.';
And bippity-boppity-boop, that's that bit done.
Code to runHaving set up the description of the mod, we do actually need to write some code that would get run when our task is called for.
The key thing here is the name of the function, and location. It should live in Sources/ScheduledTasks.php (for you mod authors, $sourcedir/ScheduledTasks.php), and go by the name of scheduled_{identifier}. So with our autoLock identifier, we want something like:
function scheduled_autoLock()
{
global $modSettings, $sourcedir, $mbname, $txt, $smcFunc, $scripturl;
$timestamp = time() - (30 * 86400);
$query = 'UPDATE {db_prefix}topics, {db_prefix}messages
SET {db_prefix}topics.locked = 1
WHERE {db_prefix}topics.id_last_msg = {db_prefix}messages.id_msg
AND {db_prefix}messages.poster_time <= {int:timestamp}';
$result = $smcFunc['db_query']('',
$query,
array(
'timestamp' => $timestamp,
)
);
return true;
}
You only have to inherit what variables you actually need, though I tend to make sure all the variables I might need are handy, and the code simply needs to run, returning true if successful, and false if not. You can check out the fuller code in the mod I mentioned, which also does it on a per-board level.
So, with that we have the description for our task, and the code for it to run.
Database workWe do also have to do one last thing - tell SMF about the task that needs to be run. Code alone is not sufficient here for that. For the mod authors out there, this last bit would be managed via an install.php and uninstall.php script as part of your mod install. Again, the technique is shown in the master version of the Auto Lock Old Topics mod.
Adding it is a simple case of adding a new row to the scheduled_tasks table, perhaps smf_scheduled_tasks. The query you'll use with $smcFunc takes the form of:
INSERT INTO {db_prefix}scheduled_tasks (id_task, next_time, time_offset, time_regularity, time_unit, disabled, task)
VALUES (NULL, 0, 0, 1, "d", 0, "autoLock")
(Of course, if we're being proper, we should be using $smcFunc['db_insert'] instead of $smcFunc['db_query']. But this way you can see what the columns are and how they relate to each other.)
Just let's quickly step through the columns:
- id_task is a numeric identifier for the row. We don't know this yet, and it's going to be assigned by SMF anyway, so leave that as NULL.
- next_time is the next time SMF is due to run the task. We set this to 0 because the task hasn't been run before.
- time_offset is the offset to run the task against, which should be the same as the forum time.
- time_regularity is the number of times per unit that this runs. For example, if running once per day, this is 1 - related to the next topic.
- time_unit is the time period considered for running the task. Supports 'm', 'h', 'd', 'w', for per minute, per hour, per day, per week. If you want to run the task daily at a set time for example, you have time_regularity as 1, and time_unit as 'd'. Once every 2 days, regularity = 2, time_unit = 'd'.
- disabled reflects if the task is disabled or not, 0 for not disabled (enabled) and 1 for disabled.
- task is the task identifier, in our case here 'autoLock'.
Once all of this is done, your scheduled task should be available to set what time you want it to run (since it will likely be different for every user)
Hopefully that's helped - if you have any questions please do ask.
Hi Arantor,
Sorry to bump this but is there any way I can make a scheduled task to run every first day of the month?
No, you'd have to have it run every 4 weeks or every 30 days. Or when it runs, have it recalculate the next interval.
hehehe :P thanks I Just figured it out after posting my message:)
What did you do in the end?
Thank you for this excellent write up!
8)
thanks for this.
i am using this guide and your auto purge mod as a basis for my first mod to delete the reference for MOVED topics to help keep the board i frequent a little cleaner.
Or you could use the Redirection Topics mod I wrote a while ago to automate that process too ;)
ha well doesnt that beat all. i searched and searched the mod site for something like this and couldnt find what i wanted. i never would have thought to use "redirection" as a keyword though.
well ya saved me a ton of time. i guess i will have to think of something else to write.
Well, the moved topics are redirection topics, they direct you to where you want to go, I also made it actually do a redirect as well.
Robbo_ now maintains the mod though.
Don't give up though, there's plenty of exciting mod possibilities :)
I would assume that with some coding you can externally estimate then date and then insert new values into the database once a month?
:o
Sure you can. But it's easier if you don't have to keep track of such things.
I agree. The code will be a PITA. :P
That's the thing, creating a scheduled task is, as above, basically a fire-and-forget situation, you define the function and matching language string, insert a row in a DB and you're basically done.
Arantor, great write up brother.
I have a question and it may be related to aED'd reply #2.
Scheduled tasks is not possible twice a day huh? I have a mod idea that i currently do manually. It has to do with members currently online.
Sure it is. Once every 12 hours - regularity 12, time unit h.
Quote from: Arantor on May 05, 2010, 01:05:49 PM
Sure it is. Once every 12 hours - regularity 12, time unit h.
Excellent.
The idea is,...... see, i have the member currently online set to 60 minutes. ...and, in the language file i changed: "Users active in past 60 minutes" to "Users online".... and changed in "features and option" the time threshold from 60 to 360.
Now it shows a lot more users online. But late at night like most forums, activity is not great. That's where the scheduled task comes in. At whatever time set, say, midnight it will revert from 360 mins to 60 mins. ....and maybe a clear cache with it.
Then in the morning say at 6am, it will revert from 60 mins to 360 mins again.
That's why asked if the schedule task can be a key player here.
Sure, in that case you create two tasks, each to run daily.
Then you just set one to run at midnight, and one to run at 6am - since the time a task is run is configurable in the ACP (and isn't related to this tutorial directly)
Quote from: Arantor on May 05, 2010, 01:34:37 PM
Sure, in that case you create two tasks, each to run daily.
Then you just set one to run at midnight, and one to run at 6am - since the time a task is run is configurable in the ACP (and isn't related to this tutorial directly)
I didnt mean to thread-jack ;)
Thanx Arantor, that cleared my questions.
Well, it's relevant - how to use scheduled tasks in a slightly different way, it's all good :)
Removed my last question and asking it in a better way :)
How should you handle if it your scheduled tasks errors? I'm logging errors using log_error(); and returning false from the Scheduled task function but the interface still happily reports that the task completed successfully, even when logging a critical error.
I'm getting the errors in the error log, which is good, but I was expecting to see that interface warn me that the manual run failed.
Hi Zaine,
it's the first time for me looking into scheduled tasks, but as far as I can understand from the code it seems that if the scheduled function returns false the task should not be logged:
// Do the task...
$completed = call_user_func('scheduled_' . $row['task']);
// Log that we did it ;)
if ($completed)
{
Here's a tip for anyone looking to run a task on a given day of the month such as the first.
Just schedule your task as a daily and do a check at the beginning to see if it is the first and then decide what code to run.
Can this be used to run a link, I have a cron job I would like SMF to handle and was wanting to schedule it for once a week. However the cron job has a link for it, and before you ask, my server won't let me run cron jobs normally..
No. No way other than the code shown in the OP.
fetch_web_data (http://support.simplemachines.org/function_db/index.php?action=view_function;id=586)? :P
Of course I mean create a function that call fetch_web_data.
Very useful tutorial. Perfect for updating my member count across multiple shared forums :) (Instead of pressing that damn recount button everyday :P)
crontab
/end thread
(sub)
I managed to create a scheduled task, but it seems like it isn't running automatically, or at least, it doesn't show on the task log..
But if i run it manually it does show on the task log..
Did i miss something?
I don't know, what did you do exactly?
Nevermind :P .. After reading through the topic again, i figured out why it wasn't working..
Quote from: Arantor on August 12, 2013, 01:08:19 AM
I don't know, what did you do exactly?
/me is reminded of The IT Crowd :P
You realise that the IT Crowd was practically a documentary rather than a comedy, right? ;)
That explains why it was so boring.
Sorry for the bump, but I need to ask for save some time, there is no hook actually for this? SMF 2.0?
I read something http://www.simplemachines.org/community/index.php?topic=510873.0
I use integrate_pre_load...
I wrote this years ago. Off the top of my head there is no hook in 2.0, the one in 2.1 is not ideal IMO.
Thanks for the responses..
Thank you, a very informative tutorial.
Very helpful article. Perfect for upgrading my new member count number across numerous contributed message boards.
(https://www.simplemachines.org/community/proxy.php?request=http%3A%2F%2Fportalpark.net%2F10204%2F11%2Fw.png&hash=0e6e204fa4bd208c4f28610d5979263d7216ca03)
Great !
I was looking for is exactly this topic!
Thank you very much ! ;)
PS :
Sorry for my english if it errors exists.
I'm french and i speak french. Only french. :(