You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This extension adds the ability to run self-configured Tasks when installed into Lucee Server.
3
+
The Tasks Event Gateway extension adds long-running background tasks to Lucee Server. Unlike cron-style schedulers that fire at fixed intervals, each task runs in its own thread loop and controls its own timing — sleep before/after execution, backoff on errors, and optional concurrency.
4
+
5
+
Use it when you need always-on workers (queue consumers, polling loops, sync jobs) rather than calendar-based scheduling. For cron expressions and one-shot jobs, see the [Quartz Scheduler extension](https://docs.lucee.org/recipes/scheduler-quartz.html).
6
+
7
+
## Requirements
8
+
9
+
- Lucee Server (single- or multi-context)
10
+
- A configured gateway instance (not created automatically since extension 1.1.0.0)
11
+
12
+
## Quick start
13
+
14
+
1. Install the extension (see [Installation](#installation)).
15
+
2. Register a gateway instance in `.CFConfig.json` or the Lucee Administrator (see [Configuration](#configuration)).
16
+
3. Create a CFC in your configured package that extends `org.lucee.cfml.Task` and implements `invoke()`.
17
+
4. Start (or restart) the gateway instance and check the configured log file for `Tasks Event Gateway:` entries.
4
18
5
19
## Build
6
20
7
21
The extension is a Maven project (which invokes Ant internally). To build it, you need Maven installed on your machine. Once available, simply run:
8
22
9
-
```
23
+
```bash
10
24
mvn package
11
25
```
12
26
@@ -16,15 +30,24 @@ within the project root. The resulting `.lex` file will be created in the `targe
16
30
17
31
## Installation
18
32
19
-
Copy the generated `.lex` file to the `/lucee-server/deploy` folder of your Lucee installation.
33
+
Install via the Lucee Administrator (**Extensions → Available**), or use any method described in the [Extension Installation recipe](https://docs.lucee.org/recipes/extension-installation.html).
34
+
35
+
Manual deploy: copy the generated `.lex` file to the `/lucee-server/deploy` folder of your Lucee installation. Lucee detects and installs it within about a minute.
Configuration happens in two places: the gateway instance configuration for global settings, and each Task/Listener implementation for Task/Listener-specific settings.
44
+
Configuration happens in two places: the gateway instance configuration for global settings, and each Task/Listener implementation for task-specific settings.
45
+
46
+
You can run multiple gateway instances (each with its own ID, package, and log). Use a shared cache in `settingLocation` when several servers need to share pause/resume state.
24
47
25
-
### Gateway Instance Configuration
48
+
### Gateway instance configuration
26
49
27
-
> **Changed in 1.1.0.0:** The extension no longer installs a gateway instance automatically. You must configure the gateway instance manually — either via `.CFConfig.json` or through the Lucee Administrator.
50
+
> **Changed in 1.1.0.0:** The extension no longer installs a gateway instance automatically. You must configure the gateway instance manually — either via `.CFConfig.json` or through **Services → Event Gateways** in the Lucee Administrator.
28
51
29
52
To register a gateway instance via `.CFConfig.json`, add an entry under the `gateways` key:
30
53
@@ -38,6 +61,7 @@ To register a gateway instance via `.CFConfig.json`, add an entry under the `gat
38
61
"custom": {
39
62
"package": "core.tasks",
40
63
"templatePath": "/cron",
64
+
"templatePathRecursive": true,
41
65
"checkForChangeInterval": 10,
42
66
"checkForChangeNoMatchInterval": 60,
43
67
"settingLocation": "",
@@ -50,89 +74,121 @@ To register a gateway instance via `.CFConfig.json`, add an entry under the `gat
50
74
}
51
75
```
52
76
53
-
The `custom` fields control the TEG behaviour:
77
+
In the Administrator, choose gateway type **Tasks**, set the instance ID (e.g. `my-task`), and fill in the same custom fields.
78
+
79
+
The `custom` fields control TEG behaviour:
54
80
55
81
| Setting | Description |
56
82
|---|---|
57
-
|`package`|The component package the TEG scans for Task/Listener CFCs (e.g. `core.tasks` maps to `/core/tasks`) |
83
+
|`package`|Component package the TEG scans for Task/Listener CFCs (e.g. `core.tasks` maps to `/core/tasks`) |
58
84
|`templatePath`| Absolute path, mapping, or webroot-relative path to a folder containing `.cfm`-based tasks |
59
-
|`checkForChangeInterval`| Seconds between file-change checks for templates previously identified as tasks. Higher values reduce I/O but slow down detection of code changes |
60
-
|`checkForChangeNoMatchInterval`| Seconds between file-change checks for templates that were **not** identified as tasks in the previous check. Typically set higher than `checkForChangeInterval`|
85
+
|`templatePathRecursive`| When `true` (default), scan `templatePath` recursively for `.cfm` task templates |
86
+
|`checkForChangeInterval`| Seconds between file-change checks for components/templates already identified as tasks. Higher values reduce I/O but slow detection of code changes |
87
+
|`checkForChangeNoMatchInterval`| Seconds between checks for files that were **not** tasks on the previous scan. Keep this higher when the folder contains many non-task files |
61
88
|`settingLocation`| Cache definition name used to persist task settings (e.g. paused state) across server instances. Leave empty if not needed |
62
-
|`checkForChangeSettingInterval`| Seconds between checks for setting changes in the `settingLocation` cache. When server A pauses a task, this is the maximum delay before server B picks up the change |
63
-
|`logName`|Name of the Lucee log file the TEG writes to (default: `application`) |
89
+
|`checkForChangeSettingInterval`| Seconds between checks for setting changes in `settingLocation`. When server A pauses a task, this is the maximum delay before server B picks up the change (`0` = disabled)|
90
+
|`logName`| Lucee log file the TEG writes to (default: `application`) |
64
91
65
-
The TEG uses four log levels:
92
+
Gateway instance settings take precedence over environment variables and JVM system properties.
66
93
67
-
-**debug** — logged during regular task execution
68
-
-**info** — logged when tasks are added, modified, or removed
69
-
-**warn** — logged when a task fails to execute
70
-
-**error** — logged when the TEG itself encounters an unexpected exception
94
+
#### Activator
71
95
72
-
#### Configuration via Environment Variables or System Properties
96
+
The activator is a component whose `active()` method returns whether the gateway should run. Default: `org.lucee.cfml.tasks.Activator` (always active). Override via JVM system property or environment variable only:
97
+
98
+
| Environment Variable | System Property | Default |
The gateway instance custom settings can also be supplied via environment variables or JVM system properties. Note that values set in the gateway instance configuration (`.CFConfig.json` or the Lucee Admin) always take precedence.
102
+
Use a custom activator for maintenance windows, feature flags, or cluster leadership.
75
103
76
-
The table below lists each environment variable alongside its system property equivalent:
104
+
#### Configuration via environment variables or system properties
77
105
78
106
| Environment Variable | System Property | Default |
When `settingLocation` is configured, pause state is persisted in cache and survives gateway restarts; with `checkForChangeSettingInterval` > 0, other servers pick up changes within that interval.
Full documentation for each property is in `/source/components/org/lucee/cfml/Task.cfc`.
160
+
| Property | Description |
161
+
|---|---|
162
+
|`concurrentThreadCount`| Number of parallel threads for this task |
163
+
|`howLongToSleepBeforeTheCall`| Milliseconds to sleep before each `invoke()`|
164
+
|`howLongToSleepAfterTheCall`| Milliseconds to sleep after a successful `invoke()`|
165
+
|`howLongToSleepAfterTheCallWhenError`| Milliseconds to sleep after an exception (prevents log spam) |
166
+
|`howLongToWaitForTaskOnStop`| Grace period when stopping the gateway before optional force-terminate |
167
+
|`forceStop`| Terminate the task thread if it does not stop within the grace period |
103
168
104
-
One setting worth highlighting: `howLongToSleepAfterTheCallWhenError` controls how long a task pauses after an exception. This is critical — you generally want a task to **slow down** after an error, not spin rapidly and flood the logs.
169
+
Full property documentation is in `source/components/org/lucee/cfml/Task.cfc`.
105
170
106
-
### Listener Configuration
171
+
### Listener configuration
107
172
108
-
Each listener configures which tasks it applies to via `allow` and `deny` properties:
173
+
Each listener configures which tasks it applies to via `allow` and `deny` properties (comma-separated lists with `*` and `?` wildcards). Deny overrides allow.
109
174
110
175
```cfc
111
176
property name="allow" type="string" default="*";
112
177
property name="deny" type="string" default="";
113
178
```
114
179
115
-
Full documentation is in `/source/components/org/lucee/cfml/Listener.cfc`.
180
+
Full documentation is in `source/components/org/lucee/cfml/Listener.cfc`.
116
181
117
182
---
118
183
119
184
## Creating a Task
120
185
121
-
The TEG scans the component package defined in the gateway instance configuration (e.g. `core.tasks`, which maps to `/core/tasks`). Any component in that package that extends `org.lucee.cfml.Task` is automatically picked up and executed.
186
+
The TEG scans the component package from gateway configuration (e.g. `core.tasks` → `/core/tasks`). Any component extending `org.lucee.cfml.Task` is picked up and executed automatically. Changes to the CFC are detected on the next scan (see `checkForChangeInterval`).
// id = thread instance id; iterations/errors = lifetime counters for this instance
202
+
systemOutput("Worker #id# iteration #iterations# at #now()#", 1, 1);
147
203
}
148
204
}
149
205
```
150
206
151
-
All properties have defaults inherited from the abstract component and are therefore optional.
207
+
All task properties inherit defaults from the abstract component and are optional.
152
208
153
-
## .cfm-Based Tasks
209
+
## .cfm-based tasks
154
210
155
-
Tasks can also be defined as plain `.cfm` templates. This is useful for reusing existing scheduled tasks without rewriting them. These tasks are executed as internal requests, so `Application.cfc` runs first.
211
+
Tasks can also be plain `.cfm` templates — useful for reusing existing scheduled templates without rewriting them. They run as internal requests, so `Application.cfc` runs first.
156
212
157
-
Set the `templatePath` in the gateway instance configuration to the folder containing your templates. Each template must include the following metadata comment to be recognised as a task:
213
+
Set `templatePath` in the gateway configuration. Each template must include task metadata in a comment block:
158
214
159
215
```cfm
160
216
<!---
161
217
@task "CFML Dummy Task"
162
-
@description "This CFML Dummy Task is just to show the functionality"
218
+
@description "Example template-based task"
163
219
@concurrentThreadCount 1
164
220
@howLongToSleepBeforeTheCall 2000
165
221
@howLongToSleepAfterTheCall 2000
166
222
@howLongToSleepAfterTheCallWhenError 10000
167
223
@howLongToWaitForTaskOnStop 10000
168
-
@forceStop true
224
+
@forceStop false
169
225
--->
170
226
```
171
227
172
-
These settings follow the same rules as property-based task configuration. Inside the template, the same arguments passed to `invoke()` are available via the `url` scope:
173
-
174
-
-`url.id`
175
-
-`url.iterations`
176
-
-`url.errors`
177
-
-`url.lastExecutionTime`
178
-
-`url.lastExecutionDate`
179
-
-`url.lastError`
228
+
Inside the template, the same arguments passed to `invoke()` are available in the `url` scope: `url.id`, `url.iterations`, `url.errors`, `url.lastExecutionTime`, `url.lastExecutionDate`, `url.lastError`.
180
229
181
230
---
182
231
183
232
## Creating a Listener
184
233
185
-
Listeners are defined the same way as tasks — they just extend a different base component. Create a component that extends `org.lucee.cfml.Listener` and implement its abstract functions:
234
+
Listeners extend `org.lucee.cfml.Listener` and implement `onExecutionStart`, `onExecutionEnd`, and `onError`. They are discovered from the same package as tasks.
0 commit comments