{"id":18924640,"url":"https://github.com/dash-os/tcl-task-manager","last_synced_at":"2026-02-11T01:32:35.106Z","repository":{"id":71821457,"uuid":"85445625","full_name":"Dash-OS/tcl-task-manager","owner":"Dash-OS","description":"Tcl Task Manager - (Command Execution Scheduler)","archived":false,"fork":false,"pushed_at":"2017-10-10T07:52:01.000Z","size":41,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-10T06:43:28.694Z","etag":null,"topics":["coroutines","every","jobs","task-manager","task-scheduler","tcl"],"latest_commit_sha":null,"homepage":null,"language":"Tcl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dash-OS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-03-19T02:27:24.000Z","updated_at":"2025-05-06T20:05:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"dcab681a-4059-49c4-b296-61fcee21d601","html_url":"https://github.com/Dash-OS/tcl-task-manager","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/Dash-OS/tcl-task-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Ftcl-task-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Ftcl-task-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Ftcl-task-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Ftcl-task-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dash-OS","download_url":"https://codeload.github.com/Dash-OS/tcl-task-manager/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Ftcl-task-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29324202,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T00:34:26.354Z","status":"ssl_error","status_checked_at":"2026-02-11T00:34:09.494Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coroutines","every","jobs","task-manager","task-scheduler","tcl"],"created_at":"2024-11-08T11:07:39.096Z","updated_at":"2026-02-11T01:32:35.089Z","avatar_url":"https://github.com/Dash-OS.png","language":"Tcl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tcl Task Manager\n\nTcl Task Manager is a powerful and lightweight task manager / scheduler which utilizes\nthe awesome capabilities of Tcl's [coroutines](https://www.tcl.tk/man/tcl/TclCmd/coroutine.htm) to \nallow us to schedule and maintain tasks which execute based on the given arguments. \n\nOne of it's important features is that it will only schedule a single `[after]` for its \ntasks so that we do not continually add more after's to our script needlessly. It will \ndetermine the next time it should wakeup based on the currently scheduled tasks then \nsleep until the next task needs to be executed.  \n\nAdditionally, if the next task is more than 10 minutes in the future, we schedule the task to wakeup \nafter 10 minutes to keep the handler fresh.\n\n`[task]` provides options to cancel, introspect, and execute your tasks in a variety of \nways such as at intervals, in a given period of time, at a specific time, and more.\n\n\n## Installation \n\nYou can use this package by simply adding the files to your system either within one of \nthe tcl module directories (`[::tcl::tm::path list]`) or to one of your `$auto_path` \ndirectories.  Once you have done this you should be able to `package require` them.\n\n\u003e **Tip:** You can add to the tcl module directories list by calling `[::tcl::tm::path add $dir]`\n\n## Optional Extras\n\nThere are a few optional \"extras\" commands which act as simple shortcut wrappers for \nconvenience.  They essentially just provide an alias to calling the `[task]` command \nfor specific use cases.  In all cases you can add them by calling `[package require tasks::$package]`.\n\nThese extras are `[at]`, `[every]`, `[in]` and are called like `[every 5000 MyProc]`.\n\n## Command Summary\n\n#### **`task`** *?...-opt ?value?...?*\n \n| Argument Name |  Type   |  Description   |\n| ------------- | ------  | -------------- |\n| -id           | String  | The id to use.  If not provided, one will be generated during creation. |\n| -ids          | List    | Adds a list of IDs to operate on. Will create multiple tasks if creating a task. |\n| -in           | [Time](#time-resolution)    | Schedules the task to execute after the given milliseconds. |\n| -at           | Unix MS | Provide the exact time to execute the task. |\n| -every        | [Time](#time-resolution)    | Execute the task every MS. |\n| -times        | Number  | Modifies every so it only executes the given # of times. |\n| -until        | Unix MS | Modifies every so it only executes until the given time. |\n| -for          | [Time](#time-resolution)    | Modifies every so it only executes for the given time. |\n| -while        | Command | Only execute the task if command is true.  Cancel every if false. |\n| -command      | Command | The command (task) to execute. |\n| [-glob](#request-flags)       | Boolean | Adds the -all and -glob flags to the request flags.  Mostly useful for -cancel where ids use glob pattern while cancelling. |\n| [-flag](#request-flags)       | String  | Adds the given flag to the list of flags to send to the request. |\n| [-flags](#request-flags)      | List    | Adds the list of flags to the flags to send to the request. |\n| [-subst](#-subst-argument)    | Boolean | Should we run `[subst -nocommands]` before calling the `-command` and `-while` requests. (Default 0) |\n| [-cancel](#task-cancellation) | Task ID | Cancels one or more tasks by their ID. |\n| [-info](#task-introspection)  | String  | Requests specific information as a response to the command. |\n\n## Time Resolution\n\nWhile most of the examples show us providing direct ms values while resolving the time, you \nmay use any values that are supported by Tcl's [clock arithmetic](http://www.tcl.tk/man/tcl8.6/TclCmd/clock.htm#M22). \nThis is handled by calling [[clock add 0 {*}$argument]](http://www.tcl.tk/man/tcl8.6/TclCmd/clock.htm#M22) then multiplying by \n1000 to get our milliseconds.  This is only done if the argument is not an entier (numeric) value. \n\nFor example, it is perfectly valid to do things like:\n\n```tcl\ntask -in {5 seconds} -command myproc\ntask -every {1 minute 20 seconds} -command myproc\ntask -every {10 seconds} -for {50 seconds} -command myproc\n```\n\n\u003e **Note:** In all situations, the values for `-in`, `-every`, and `-for` are converted to an absolute \n\u003e time by doing something like `[expr { [clock milliseconds] + [::task::time $arg] }]`. \n\n## Request Flags\n\nFlags can be provided during a request.  These allow modification to how the request will handle itself.  At \nthis time they are used during a `-cancel` request to modify how we search for the matching id's to cancel.\n\nFlags are provided in a few different ways.  There are shortcut flags (-glob) which are defined directly to \n`[task]` as well as the -flag (single flag) and -flags (list of flags) options.\n\n```tcl\ntask -id foo_bar -in {5 seconds} -command myproc\ntask -id foo_bax -in 5000 -command myproc\ntask -id foo_qux -in 10000 -command myproc\ntask -id bar -in 5000 -command myproc\n\n# Cancel all tasks that start with foo\ntask -glob -cancel foo*\n\n#### -- OR -- ####\n\n# Cancel all tasks that don't start with foo\ntask -flags [list -all -not -glob] -cancel foo*\n# The above is also synonymous with:\ntask -glob -flags [list -not] -cancel foo*\n# and\ntask -glob -flag -not -cancel foo*\n```\n\n\u003e **Tip:** By default the lsearch command that looks for the id's that we want to cancel has the `-exact` flag added to it. \n\u003e Adding flags allows you to override that in this case.\n\n## Command Examples\n\n\u003e **Note:** In all examples we will need to be setup to receive from the tcl event loop. \n\u003e For the sake of redundancy we are not adding something like `[vwait _forever_]` in the \n\u003e examples, but that or similar will be required.\n\n```tcl\npackage require task\n\nproc MyProc args {\n  puts \"[clock milliseconds] | MyProc Executes | $args\"\n}\n\n# Execute the task once, in 5 seconds with no arguments and an auto assigned id\nset task_id [ task -in 5000 -command MyProc ]\n\n# Trigger MyProc every 5 seconds.  The tasks id is my_task\ntask -id my_task -every 5000 -command [list MyProc my_task]\n\n# Scheduling a new task with the same id will replace the previous\ntask -id my_task -every 5000 -command [list MyProc my_task]\n\n# Trigger MyProc every 5 seconds for 5 cycles\ntask -every 5000 -times 5 -command [list MyProc five_times]\n\n# Trigger MyProc every 5 seconds for 60 seconds\ntask -every 5000 -for 60000 -command [list MyProc sixty_seconds]\n\n# Trigger MyProc every 5 seconds until the given unix timestamp in ms.\ntask -every 5000 -until [expr { [clock milliseconds] + 60000 }] -command [list MyProc every_until_unix_ms]\n\n# Trigger MyProc at the given unix timestamp in ms.\ntask -at [expr { [clock milliseconds] + 5000 }] -command [list MyProc at_unix_ms]\n\n# Now lets add a command that we can use to test if we should continue execution\n\nset i 0\nproc RunWhile args {\n  variable i ; incr i\n  if { $args ne {} } {\n    lassign $args task_id\n    if { $task_id ne {} \u0026\u0026 $i \u003e 30 } { return 0 }\n  } elseif { $i \u003e 5 } { return 0 }\n  return 1\n}\n\n# Run the every command every 5 seconds for 5 overall calls of RunWhile\ntask -every 5000 -while RunWhile -command [list MyProc run_while_true]\n\n# Run the every command every 5 seconds for 30 calls of RunWhile - feed our $task_id to -while and -command.\ntask -subst 1 -every 5000 -while {RunWhile $task_id} -command {MyProc $task_id}  \n\n```\n\n### Task Cancellation\n\nYou can cancel scheduled tasks easily by providing the `-cancel` argument.  It accepts a \nstring or list of task_id(s) that should be cancelled.  The response value of the cancellation \nwill be the number of tasks which were cancelled (if any).  This is helpful when using glob-style \ncancellation as discussed in the above [flags](#request-flags) section.\n\n```tcl\npackage require task\n\nproc myproc args {\n  # ... do something\n}\n\ntask -every 5000 -id my_task -command myproc\nset task_id [ task -in 5000 -command myproc ]\nset task2_id [ task -in 5000 -command myproc ]\n\ntask -cancel [list my_task $task_id]\ntask -cancel $task2_id\n\n# Technically this also works, although the above is less verbose.\n# task -cancel -ids [list my_task $task_id]\n# task -cancel -id $task2_id\n\n# Using introspection you can do something like below to cancel all scheduled tasks.\n# task -cancel [task -info ids]\n```\n\n#### Modifying Cancellation Response Value\n\nSometimes you may want to receive the task id's that were cancelled rather than the total \nnumber of tasks.  Or perhaps another value?  You may use the -info option with cancellation \nto control the value which will be returned.\n\nWhile there are more possibilities (see below tip), the main use would be to request that a list \nof `task_id`'s are returned instead of the total cancelled. \n\n```tcl\n# default (\"-info total\" is not required)\nset total_cancelled [ task -glob -cancel myprefix* -info total ]\n\n# get a list of cancelled id's rather than the total cancelled\nset cancelled_ids   [ task -glob -cancel myprefix* -info ids ]\n```\n\n\u003e **Tip:** This simply returns a `[set $value]` so any of the variables known to the `[::task::remove_tasks]`\n\u003e proc may be given.  \n\n### -subst argument\n\nBy providing the `-subst 1` argument, you are instructing the task manager to subst the given \ncommand before execution.  This allows you to add arguments from our execution environment \nbefore running the command.  \n\nThis is useful, for example, to capture the executed task_id or to get the currently scheduled \ntasks.  Below is a list of variables that you can capture for any `-while` or `-command` executions \nif the `-subst` argument is set to true.  \n\n\u003e **Note:** By default this is 0 and no substitution will be attempted.\n\n| Variable Name   |  Description   |\n| -------------   | -------------- |\n| $task_id        | This will always resolve to the task_id of the task that is being evaluated. |\n| $tasks          | The dict that holds all currently scheduled tasks (not including the current task).  |\n| $task           | The current tasks descriptor that defines its arguments. |\n| $scheduled      | The key/value list of task_id's to time_scheduled values (not including the current task). |\n\n```tcl\npackage require task\n\nproc myproc {id remaining_tasks} {\n  # ... do stuff\n}\n\ntask -subst 1 -every 5000 -command {myproc $task_id $tasks}\n```\n\n### Task Introspection\n\n#### **`task`** -info $value\n\nThe package introduces a fairly simple introspection capability that can allow you \nto get some information about the currently scheduled tasks.  \n\n| Argument Name |  Description   |\n| ------------- | -------------- |\n| task / tasks  | Get a dict of the currently scheduled tasks.  If -id is provided, returns that task only. |\n| scheduled     | Returns a dict of $task_id / $time_scheduled pairs. |\n| ids           | Returns a list of the currently scheduled task ids. |\n| next_id       | Returns the id of the next task that will be executed. |\n| next_time     | Returns the time that the next task will be executed. |\n| next_task     | Returns the descriptor dict of the next task that will be executed. |\n| next          | Returns a three element list: [list $next_id $next_time $next_task] |\n\n```tcl\npackage require task\n\nproc myproc args { \n  # ... do stuff\n}\n\ntask -every 5000 -command myproc\ntask -in 10000 -command myproc\ntask -in 15000 -command myproc\ntask -id my_task -every 2000 -times 5 -command myproc\n\n# Now we can run introspection commands\n\nset next [task -info next] \n# my_task 1489896518265 {every 2000 times 5 cmd myproc}\n\nset ids  [task -info ids] \n# task#1 task#2 task#3 my_task\n\nset task [task -info task -id my_task]\n# every 5000 times 5 cmd myproc\n\nset tasks [task -info tasks]\n# task#1 {every 5000 cmd myproc} task#2 {cmd myproc} task#3 {cmd myproc} \n# my_task {every 2000 times 5 cmd myproc}\n\nset scheduled [task -info scheduled]\n# my_task 1489896708158 task#1 1489896711158 \n# task#2 1489896716158 task#3 1489896721158\n\n```\n\n\u003e **Note:** The \"times\" key within the descriptor will be updated with how many \n\u003e executions are remaining so it might be difference depending on when it is \n\u003e called.\n\n## Extras Examples\n\nAll of the commands below can also take the normal `[task]` arguments optionally. \nAll of these commands will operate together - you will still always have a single \nset of tasks that are managed by `[task]`. \n\n\u003e As these are found in the \"tasks\" folder, we require it by providing the \n\u003e directory followed by \"::\" then the package name.  This is defined by the \n\u003e Tcl [tm](https://www.tcl.tk/man/tcl/TclCmd/tm.htm) packages instructions.\n\n#### **`every`** $interval_ms $cmd\n\n```tcl\npackage require tasks::every\n\nset every_id [every 5000 {puts hi}]\n\n# sometime later\n\nevery cancel $every_id\n\n```\n\n#### **`in`** $ms $cmd\n\n```tcl\npackage require tasks::in\n\nset in_id [in 5000 {puts hi}]\n\n# can be cancelled with [in cancel $in_id]\n\n```\n\n\u003e Note this is almost identical to [after] except that scheduling many will only \n\u003e actually schedule [after] one total time.  You may also call it with the other \n\u003e `[task]` arguments to enhance its capabilities.\n\n#### **`at`** $time $cmd\n\n```tcl\npackage require tasks::at\n\nset at_id [at [expr { [clock milliseconds] + 5000 }] {puts hi}]\n\n# can be cancelled with [at cancel $at_id]\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdash-os%2Ftcl-task-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdash-os%2Ftcl-task-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdash-os%2Ftcl-task-manager/lists"}