taski 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +40 -21
- data/docs/GUIDE.md +340 -0
- data/examples/README.md +65 -17
- data/examples/{context_demo.rb → args_demo.rb} +27 -27
- data/examples/clean_demo.rb +204 -0
- data/examples/group_demo.rb +113 -0
- data/examples/reexecution_demo.rb +93 -80
- data/examples/system_call_demo.rb +56 -0
- data/lib/taski/{context.rb → args.rb} +3 -3
- data/lib/taski/execution/execution_context.rb +379 -0
- data/lib/taski/execution/executor.rb +408 -117
- data/lib/taski/execution/registry.rb +17 -1
- data/lib/taski/execution/scheduler.rb +308 -0
- data/lib/taski/execution/task_output_pipe.rb +42 -0
- data/lib/taski/execution/task_output_router.rb +216 -0
- data/lib/taski/execution/task_wrapper.rb +210 -40
- data/lib/taski/execution/tree_progress_display.rb +385 -98
- data/lib/taski/execution/worker_pool.rb +104 -0
- data/lib/taski/section.rb +16 -3
- data/lib/taski/task.rb +222 -36
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +138 -23
- data/sig/taski.rbs +207 -27
- metadata +13 -7
- data/docs/advanced-features.md +0 -625
- data/docs/api-guide.md +0 -509
- data/docs/error-handling.md +0 -684
- data/examples/section_progress_demo.rb +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0e593418f036752e5adf6bb989cfc800ee249be3b3a7ace71df377a5aa1b73bf
|
|
4
|
+
data.tar.gz: 4e69af8247ade3e1e585475dcab88ae73fa42a71a60d4bbcc420456b1b2d9de5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 339d64fa997095a68adffa2d7227c5e648dc147edf576824283328a1e655706d6e72666fd56a8d8f934283ddd399eb691467121381f995b8540c798bb7f28c87
|
|
7
|
+
data.tar.gz: 3d5d41b708ab1d9f715bc0848d22b7b4233b50b6f922440ec304fb3c32a2b86bddf936839387462370a8b2df0e9de9d8200b9733aa8fdafdf3fa2536e21835ab
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.7.0] - 2025-12-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Group block for organizing progress display messages (`Taski.group`) ([#105](https://github.com/ahogappa/taski/pull/105))
|
|
14
|
+
- Scope-based execution with thread-local registry for independent task execution ([#103](https://github.com/ahogappa/taski/pull/103))
|
|
15
|
+
- `TaskClass::Error` auto-generation for task-specific error handling ([#95](https://github.com/ahogappa/taski/pull/95))
|
|
16
|
+
- `AggregateAware` module for transparent rescue matching with `AggregateError` ([#95](https://github.com/ahogappa/taski/pull/95))
|
|
17
|
+
- `AggregateError#includes?` and `AggregateError#find` methods for searching aggregated errors ([#95](https://github.com/ahogappa/taski/pull/95))
|
|
18
|
+
- Aggregation of multiple errors in parallel execution ([#95](https://github.com/ahogappa/taski/pull/95))
|
|
19
|
+
- `workers` parameter to `Task.run`, `Task.clean`, and `Task.run_and_clean` for configurable parallelism ([#92](https://github.com/ahogappa/taski/pull/92))
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Renamed `context` to `args` for API clarity (BREAKING CHANGE) ([#94](https://github.com/ahogappa/taski/pull/94))
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- Thread-safety improvements in `Registry#get_or_create` ([#90](https://github.com/ahogappa/taski/pull/90))
|
|
26
|
+
|
|
27
|
+
## [0.6.0] - 2025-12-21
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- `Task#system` override for capturing subprocess output in progress display
|
|
31
|
+
- `ExecutionContext` with observer pattern for managing execution state
|
|
32
|
+
- Inline task output display in progress tree
|
|
33
|
+
- Clean execution with reverse dependency order via `run_and_clean`
|
|
34
|
+
- Comprehensive documentation for `TaskAbortException`
|
|
35
|
+
- Unit tests for `ExecutionContext`, `WorkerPool`, and `Scheduler`
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- Replaced `ThreadOutputCapture` with pipe-based `TaskOutputRouter` for more reliable output capture
|
|
39
|
+
- Split `Executor` into separate `Scheduler` and `WorkerPool` classes for better separation of concerns
|
|
40
|
+
- Centralized tree building logic in `TreeProgressDisplay`
|
|
41
|
+
- Improved `run_and_clean` implementation and display
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- Added mutex protection to `impl_call_order` accessor for thread safety
|
|
45
|
+
- Fixed `ExecutionContext` passing to `TaskWrapper` resolving progress display garbage
|
|
46
|
+
- Improved output capture reliability for progress display
|
|
47
|
+
|
|
48
|
+
## [0.5.0] - 2025-11-30
|
|
49
|
+
|
|
50
|
+
- Initial release with core task execution functionality
|
data/README.md
CHANGED
|
@@ -115,7 +115,7 @@ end
|
|
|
115
115
|
|
|
116
116
|
## Advanced Usage
|
|
117
117
|
|
|
118
|
-
###
|
|
118
|
+
### Args - Runtime Information and Options
|
|
119
119
|
|
|
120
120
|
Pass custom options and access execution context from any task:
|
|
121
121
|
|
|
@@ -123,43 +123,62 @@ Pass custom options and access execution context from any task:
|
|
|
123
123
|
class DeployTask < Taski::Task
|
|
124
124
|
def run
|
|
125
125
|
# User-defined options
|
|
126
|
-
env = Taski.
|
|
127
|
-
debug = Taski.
|
|
126
|
+
env = Taski.args[:env]
|
|
127
|
+
debug = Taski.args.fetch(:debug, false)
|
|
128
128
|
|
|
129
129
|
# Runtime information
|
|
130
|
-
puts "Working directory: #{Taski.
|
|
131
|
-
puts "Started at: #{Taski.
|
|
132
|
-
puts "Root task: #{Taski.
|
|
130
|
+
puts "Working directory: #{Taski.args.working_directory}"
|
|
131
|
+
puts "Started at: #{Taski.args.started_at}"
|
|
132
|
+
puts "Root task: #{Taski.args.root_task}"
|
|
133
133
|
puts "Deploying to: #{env}"
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
# Pass options when running
|
|
138
|
-
DeployTask.run(
|
|
138
|
+
DeployTask.run(args: { env: "production", debug: true })
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
- `Taski.
|
|
143
|
-
- `Taski.
|
|
144
|
-
- `Taski.
|
|
145
|
-
- `Taski.
|
|
146
|
-
- `Taski.
|
|
147
|
-
- `Taski.
|
|
141
|
+
Args API:
|
|
142
|
+
- `Taski.args[:key]` - Get option value (nil if not set)
|
|
143
|
+
- `Taski.args.fetch(:key, default)` - Get with default value
|
|
144
|
+
- `Taski.args.key?(:key)` - Check if option exists
|
|
145
|
+
- `Taski.args.working_directory` - Execution directory
|
|
146
|
+
- `Taski.args.started_at` - Execution start time
|
|
147
|
+
- `Taski.args.root_task` - First task class called
|
|
148
148
|
|
|
149
|
-
###
|
|
149
|
+
### Execution Model
|
|
150
150
|
|
|
151
151
|
```ruby
|
|
152
|
-
#
|
|
152
|
+
# Each class method call creates fresh execution
|
|
153
153
|
RandomTask.value # => 42
|
|
154
|
-
RandomTask.value # =>
|
|
154
|
+
RandomTask.value # => 99 (different value - fresh execution)
|
|
155
155
|
|
|
156
|
-
#
|
|
157
|
-
RandomTask.new
|
|
156
|
+
# Instance-level caching
|
|
157
|
+
instance = RandomTask.new
|
|
158
|
+
instance.run # => 42
|
|
159
|
+
instance.run # => 42 (cached within instance)
|
|
160
|
+
instance.value # => 42
|
|
158
161
|
|
|
159
|
-
#
|
|
160
|
-
RandomTask
|
|
162
|
+
# Dependencies within same execution share results
|
|
163
|
+
DoubleConsumer.run # RandomTask runs once, both accesses get same value
|
|
161
164
|
```
|
|
162
165
|
|
|
166
|
+
### Aborting Execution
|
|
167
|
+
|
|
168
|
+
Stop all pending tasks when a critical error occurs:
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
class CriticalTask < Taski::Task
|
|
172
|
+
def run
|
|
173
|
+
if fatal_error?
|
|
174
|
+
raise Taski::TaskAbortException, "Cannot continue"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
When `TaskAbortException` is raised, no new tasks will start. Already running tasks will complete, then execution stops.
|
|
181
|
+
|
|
163
182
|
### Progress Display
|
|
164
183
|
|
|
165
184
|
Tree-based progress visualization is enabled by default:
|
data/docs/GUIDE.md
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Taski Guide
|
|
2
|
+
|
|
3
|
+
This guide provides detailed documentation beyond the basics covered in the README.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Error Handling](#error-handling)
|
|
8
|
+
- [Lifecycle Management](#lifecycle-management)
|
|
9
|
+
- [Progress Display](#progress-display)
|
|
10
|
+
- [Debugging](#debugging)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Error Handling
|
|
15
|
+
|
|
16
|
+
Taski provides comprehensive error handling for parallel task execution.
|
|
17
|
+
|
|
18
|
+
### Error Types
|
|
19
|
+
|
|
20
|
+
| Exception | Purpose |
|
|
21
|
+
|-----------|---------|
|
|
22
|
+
| `Taski::AggregateError` | Multiple tasks failed during parallel execution |
|
|
23
|
+
| `Taski::TaskError` | Base class for task-specific errors |
|
|
24
|
+
| `Taski::TaskAbortException` | Intentional abort (stops all tasks immediately) |
|
|
25
|
+
| `Taski::CircularDependencyError` | Circular dependency detected |
|
|
26
|
+
| `TaskClass::Error` | Auto-generated error class for each Task subclass |
|
|
27
|
+
|
|
28
|
+
### AggregateError
|
|
29
|
+
|
|
30
|
+
When multiple tasks fail during parallel execution, errors are collected into an `AggregateError`:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
class DatabaseTask < Taski::Task
|
|
34
|
+
exports :connection
|
|
35
|
+
def run
|
|
36
|
+
raise "Database connection failed"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class CacheTask < Taski::Task
|
|
41
|
+
exports :redis_client
|
|
42
|
+
def run
|
|
43
|
+
raise "Cache connection failed"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class AppTask < Taski::Task
|
|
48
|
+
def run
|
|
49
|
+
db = DatabaseTask.connection
|
|
50
|
+
cache = CacheTask.redis_client
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
begin
|
|
55
|
+
AppTask.run
|
|
56
|
+
rescue Taski::AggregateError => e
|
|
57
|
+
puts "#{e.errors.size} tasks failed:"
|
|
58
|
+
e.errors.each do |failure|
|
|
59
|
+
puts " - #{failure.task_class.name}: #{failure.error.message}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
# Output:
|
|
63
|
+
# 2 tasks failed:
|
|
64
|
+
# - DatabaseTask: Database connection failed
|
|
65
|
+
# - CacheTask: Cache connection failed
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Task-Specific Error Classes
|
|
69
|
+
|
|
70
|
+
Each Task subclass automatically gets an `::Error` class for targeted rescue:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
class DatabaseTask < Taski::Task
|
|
74
|
+
exports :connection
|
|
75
|
+
def run
|
|
76
|
+
raise "Connection failed"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Rescue errors from a specific task
|
|
81
|
+
begin
|
|
82
|
+
AppTask.run
|
|
83
|
+
rescue DatabaseTask::Error => e
|
|
84
|
+
puts "Database task failed: #{e.message}"
|
|
85
|
+
# e.task_class returns DatabaseTask
|
|
86
|
+
# e.cause returns the original error
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This works transparently with `AggregateError` - when you rescue `DatabaseTask::Error`, it matches an `AggregateError` that contains a `DatabaseTask::Error`.
|
|
91
|
+
|
|
92
|
+
### TaskAbortException
|
|
93
|
+
|
|
94
|
+
Use `TaskAbortException` to immediately stop all task execution:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
class CriticalTask < Taski::Task
|
|
98
|
+
def run
|
|
99
|
+
if critical_condition_met?
|
|
100
|
+
raise Taski::TaskAbortException, "Critical error - aborting"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`TaskAbortException` takes priority over regular errors. Already running tasks will complete, but no new tasks will start.
|
|
107
|
+
|
|
108
|
+
### Error Handling Best Practices
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# 1. Handle errors within the task when recovery is possible
|
|
112
|
+
class ResilientTask < Taski::Task
|
|
113
|
+
exports :data
|
|
114
|
+
def run
|
|
115
|
+
@data = fetch_from_primary
|
|
116
|
+
rescue Timeout::Error
|
|
117
|
+
@data = fetch_from_fallback
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# 2. Use task-specific errors for clarity
|
|
122
|
+
begin
|
|
123
|
+
AppTask.run
|
|
124
|
+
rescue DatabaseTask::Error => e
|
|
125
|
+
handle_database_failure(e)
|
|
126
|
+
rescue CacheTask::Error => e
|
|
127
|
+
handle_cache_failure(e)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# 3. Fail fast with clear messages
|
|
131
|
+
class ValidatingTask < Taski::Task
|
|
132
|
+
def run
|
|
133
|
+
missing = %w[DATABASE_URL API_KEY].select { |v| ENV[v].nil? }
|
|
134
|
+
raise "Missing: #{missing.join(', ')}" if missing.any?
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Lifecycle Management
|
|
142
|
+
|
|
143
|
+
Taski supports resource cleanup with `run`, `clean`, and `run_and_clean` methods.
|
|
144
|
+
|
|
145
|
+
### Basic Lifecycle
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
class DatabaseSetup < Taski::Task
|
|
149
|
+
exports :connection
|
|
150
|
+
|
|
151
|
+
def run
|
|
152
|
+
@connection = "postgresql://localhost:5432/myapp"
|
|
153
|
+
puts "Database connected"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def clean
|
|
157
|
+
puts "Database disconnected"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
class WebServer < Taski::Task
|
|
162
|
+
def run
|
|
163
|
+
puts "Server started with #{DatabaseSetup.connection}"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def clean
|
|
167
|
+
puts "Server stopped"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Start
|
|
172
|
+
WebServer.run
|
|
173
|
+
# => Database connected
|
|
174
|
+
# => Server started with postgresql://localhost:5432/myapp
|
|
175
|
+
|
|
176
|
+
# Clean (reverse dependency order)
|
|
177
|
+
WebServer.clean
|
|
178
|
+
# => Server stopped
|
|
179
|
+
# => Database disconnected
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### run_and_clean
|
|
183
|
+
|
|
184
|
+
Execute run followed by clean in a single operation:
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
WebServer.run_and_clean
|
|
188
|
+
# => Database connected
|
|
189
|
+
# => Server started
|
|
190
|
+
# => Server stopped
|
|
191
|
+
# => Database disconnected
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Idempotent Clean Methods
|
|
195
|
+
|
|
196
|
+
Clean methods should be safe to call multiple times:
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
class SafeFileTask < Taski::Task
|
|
200
|
+
exports :data_file
|
|
201
|
+
|
|
202
|
+
def run
|
|
203
|
+
@data_file = '/tmp/data.txt'
|
|
204
|
+
File.write(@data_file, 'data')
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def clean
|
|
208
|
+
# Check before delete
|
|
209
|
+
if @data_file && File.exist?(@data_file)
|
|
210
|
+
File.delete(@data_file)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Progress Display
|
|
219
|
+
|
|
220
|
+
Taski provides real-time progress visualization during task execution.
|
|
221
|
+
|
|
222
|
+
### Features
|
|
223
|
+
|
|
224
|
+
- **Spinner Animation**: Animated spinner during execution
|
|
225
|
+
- **Output Capture**: Real-time display of task output (last line)
|
|
226
|
+
- **Status Indicators**: Success/failure icons with execution time
|
|
227
|
+
- **Group Blocks**: Organize output messages into logical phases
|
|
228
|
+
- **TTY Detection**: Clean output when redirected to files
|
|
229
|
+
|
|
230
|
+
### Group Blocks
|
|
231
|
+
|
|
232
|
+
Use `group` blocks to organize output within a task into logical phases. The current group name is displayed alongside the task's output in the progress display.
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
class DeployTask < Taski::Task
|
|
236
|
+
def run
|
|
237
|
+
group("Preparing environment") do
|
|
238
|
+
puts "Checking dependencies..."
|
|
239
|
+
puts "Validating config..."
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
group("Building application") do
|
|
243
|
+
puts "Compiling source..."
|
|
244
|
+
puts "Running tests..."
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
group("Deploying") do
|
|
248
|
+
puts "Uploading files..."
|
|
249
|
+
puts "Restarting server..."
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Progress display output:
|
|
256
|
+
|
|
257
|
+
```text
|
|
258
|
+
During execution:
|
|
259
|
+
⠋ DeployTask (Task) | Deploying: Uploading files...
|
|
260
|
+
|
|
261
|
+
After completion:
|
|
262
|
+
✓ DeployTask (Task) 520ms
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The group name appears as a prefix to the output message: `| GroupName: output...`
|
|
266
|
+
|
|
267
|
+
Groups are useful for:
|
|
268
|
+
- **Logical organization**: Group related operations together
|
|
269
|
+
- **Progress visibility**: See which phase is currently executing
|
|
270
|
+
- **Error context**: Know which phase failed when errors occur
|
|
271
|
+
|
|
272
|
+
### Example Output
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
During execution:
|
|
276
|
+
WebServer (Task)
|
|
277
|
+
├── Config (Task) ...
|
|
278
|
+
│ ├── Database (Task) 45.2ms
|
|
279
|
+
│ └── Cache (Task) ...
|
|
280
|
+
└── Server (Task)
|
|
281
|
+
|
|
282
|
+
After completion:
|
|
283
|
+
WebServer (Task) 120.5ms
|
|
284
|
+
├── Config (Task) 50.3ms
|
|
285
|
+
│ ├── Database (Task) 45.2ms
|
|
286
|
+
│ └── Cache (Task) 48.1ms
|
|
287
|
+
└── Server (Task) 70.2ms
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Disabling Progress Display
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
TASKI_PROGRESS_DISABLE=1 ruby your_script.rb
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### File Output Mode
|
|
297
|
+
|
|
298
|
+
When output is redirected, interactive spinners are automatically disabled:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
ruby build.rb > build.log 2>&1
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Debugging
|
|
307
|
+
|
|
308
|
+
### Environment Variables
|
|
309
|
+
|
|
310
|
+
| Variable | Purpose |
|
|
311
|
+
|----------|---------|
|
|
312
|
+
| `TASKI_PROGRESS_DISABLE=1` | Disable progress display |
|
|
313
|
+
| `TASKI_DEBUG=1` | Enable debug output |
|
|
314
|
+
|
|
315
|
+
### Dependency Tree Visualization
|
|
316
|
+
|
|
317
|
+
```ruby
|
|
318
|
+
puts MyTask.tree
|
|
319
|
+
# MyTask (Task)
|
|
320
|
+
# ├── DatabaseTask (Task)
|
|
321
|
+
# └── CacheTask (Task)
|
|
322
|
+
# └── ConfigTask (Task)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Common Issues
|
|
326
|
+
|
|
327
|
+
**Circular Dependencies**
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
# Detected before execution
|
|
331
|
+
begin
|
|
332
|
+
TaskA.run
|
|
333
|
+
rescue Taski::CircularDependencyError => e
|
|
334
|
+
puts e.cyclic_tasks # [[TaskA, TaskB]]
|
|
335
|
+
end
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Static Analysis Requirements**
|
|
339
|
+
|
|
340
|
+
Tasks must be defined in source files (not dynamically with `Class.new`) because static analysis uses Prism AST parsing which requires actual source files.
|
data/examples/README.md
CHANGED
|
@@ -34,36 +34,36 @@ ruby examples/section_demo.rb
|
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
37
|
-
### 3.
|
|
37
|
+
### 3. args_demo.rb - Runtime Args and Options
|
|
38
38
|
|
|
39
|
-
Access execution
|
|
39
|
+
Access execution args and pass custom options to tasks.
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
ruby examples/
|
|
42
|
+
ruby examples/args_demo.rb
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
**Covers:**
|
|
46
|
-
- User-defined options via `run(
|
|
47
|
-
- `Taski.
|
|
48
|
-
- `Taski.
|
|
49
|
-
- `Taski.
|
|
50
|
-
- `Taski.
|
|
51
|
-
- `Taski.
|
|
46
|
+
- User-defined options via `run(args: {...})`
|
|
47
|
+
- `Taski.args[:key]` for option access
|
|
48
|
+
- `Taski.args.fetch(:key, default)` for defaults
|
|
49
|
+
- `Taski.args.working_directory`
|
|
50
|
+
- `Taski.args.started_at`
|
|
51
|
+
- `Taski.args.root_task`
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
|
-
### 4. reexecution_demo.rb -
|
|
55
|
+
### 4. reexecution_demo.rb - Scope-Based Execution
|
|
56
56
|
|
|
57
|
-
Understand
|
|
57
|
+
Understand scope-based execution and caching behavior.
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
ruby examples/reexecution_demo.rb
|
|
60
|
+
TASKI_PROGRESS_DISABLE=1 ruby examples/reexecution_demo.rb
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
**Covers:**
|
|
64
|
-
-
|
|
65
|
-
- `Task.new`
|
|
66
|
-
-
|
|
64
|
+
- Fresh execution for each class method call
|
|
65
|
+
- Instance-level caching with `Task.new`
|
|
66
|
+
- Scope-based dependency caching
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
@@ -97,16 +97,64 @@ ruby examples/parallel_progress_demo.rb
|
|
|
97
97
|
|
|
98
98
|
---
|
|
99
99
|
|
|
100
|
+
### 7. clean_demo.rb - Lifecycle Management
|
|
101
|
+
|
|
102
|
+
Demonstrates resource cleanup with clean methods.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
ruby examples/clean_demo.rb
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Covers:**
|
|
109
|
+
- Defining `clean` methods for resource cleanup
|
|
110
|
+
- Reverse dependency order execution
|
|
111
|
+
- `run_and_clean` combined operation
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### 8. system_call_demo.rb - Subprocess Output
|
|
116
|
+
|
|
117
|
+
Capture subprocess output in progress display.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
ruby examples/system_call_demo.rb
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Covers:**
|
|
124
|
+
- `system()` output capture
|
|
125
|
+
- Streaming output display
|
|
126
|
+
- Parallel subprocess execution
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### 9. nested_section_demo.rb - Nested Sections
|
|
131
|
+
|
|
132
|
+
Sections that depend on other tasks for implementation selection.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
TASKI_PROGRESS_DISABLE=1 ruby examples/nested_section_demo.rb
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Covers:**
|
|
139
|
+
- Section inside Section
|
|
140
|
+
- Dynamic implementation selection
|
|
141
|
+
- Complex dependency hierarchies
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
100
145
|
## Quick Reference
|
|
101
146
|
|
|
102
147
|
| Example | Feature | Complexity |
|
|
103
148
|
|---------|---------|------------|
|
|
104
149
|
| quick_start | Exports API | Basic |
|
|
105
150
|
| section_demo | Section API | Intermediate |
|
|
106
|
-
|
|
|
107
|
-
| reexecution_demo |
|
|
151
|
+
| args_demo | Args API | Intermediate |
|
|
152
|
+
| reexecution_demo | Scope-Based Execution | Intermediate |
|
|
108
153
|
| data_pipeline_demo | ETL Pipeline | Advanced |
|
|
109
154
|
| parallel_progress_demo | Progress Display | Advanced |
|
|
155
|
+
| clean_demo | Lifecycle Management | Intermediate |
|
|
156
|
+
| system_call_demo | Subprocess Output | Advanced |
|
|
157
|
+
| nested_section_demo | Nested Sections | Advanced |
|
|
110
158
|
|
|
111
159
|
## Running All Examples
|
|
112
160
|
|