taski 0.8.3 → 0.9.1
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 +52 -0
- data/README.md +108 -50
- data/docs/GUIDE.md +79 -55
- data/examples/README.md +10 -29
- data/examples/clean_demo.rb +25 -65
- data/examples/large_tree_demo.rb +356 -0
- data/examples/message_demo.rb +0 -1
- data/examples/progress_demo.rb +13 -24
- data/examples/reexecution_demo.rb +8 -44
- data/lib/taski/execution/execution_facade.rb +150 -0
- data/lib/taski/execution/executor.rb +167 -359
- data/lib/taski/execution/fiber_protocol.rb +27 -0
- data/lib/taski/execution/registry.rb +15 -19
- data/lib/taski/execution/scheduler.rb +161 -140
- data/lib/taski/execution/task_observer.rb +41 -0
- data/lib/taski/execution/task_output_router.rb +41 -58
- data/lib/taski/execution/task_wrapper.rb +123 -219
- data/lib/taski/execution/worker_pool.rb +279 -64
- data/lib/taski/logging.rb +105 -0
- data/lib/taski/progress/layout/base.rb +600 -0
- data/lib/taski/progress/layout/filters.rb +126 -0
- data/lib/taski/progress/layout/log.rb +27 -0
- data/lib/taski/progress/layout/simple.rb +166 -0
- data/lib/taski/progress/layout/tags.rb +76 -0
- data/lib/taski/progress/layout/theme_drop.rb +84 -0
- data/lib/taski/progress/layout/tree.rb +300 -0
- data/lib/taski/progress/theme/base.rb +224 -0
- data/lib/taski/progress/theme/compact.rb +58 -0
- data/lib/taski/progress/theme/default.rb +25 -0
- data/lib/taski/progress/theme/detail.rb +48 -0
- data/lib/taski/progress/theme/plain.rb +40 -0
- data/lib/taski/static_analysis/analyzer.rb +5 -17
- data/lib/taski/static_analysis/dependency_graph.rb +19 -1
- data/lib/taski/static_analysis/start_dep_analyzer.rb +400 -0
- data/lib/taski/static_analysis/visitor.rb +1 -39
- data/lib/taski/task.rb +49 -58
- data/lib/taski/task_proxy.rb +59 -0
- data/lib/taski/test_helper/errors.rb +1 -1
- data/lib/taski/test_helper.rb +22 -36
- data/lib/taski/version.rb +1 -1
- data/lib/taski.rb +62 -61
- data/sig/taski.rbs +194 -203
- metadata +34 -8
- data/examples/section_demo.rb +0 -195
- data/lib/taski/execution/base_progress_display.rb +0 -393
- data/lib/taski/execution/execution_context.rb +0 -390
- data/lib/taski/execution/plain_progress_display.rb +0 -76
- data/lib/taski/execution/simple_progress_display.rb +0 -247
- data/lib/taski/execution/tree_progress_display.rb +0 -643
- data/lib/taski/section.rb +0 -74
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c7ea0740de2f0d1fcf24a72fe5b32e75128fa4d793718b3ac12a2c041c37628
|
|
4
|
+
data.tar.gz: 8fb45c4d390a98709d934f4b59f14a613d689ed7538df630cb4328bc405b2803
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7cba0b749c9f5b5e76f990731017d18c550407215f851877129d2c6b1c9872fccfb3d0e088b01db19a92064f92592971a085ca9eecca3bcd8742e44b7374a9e5
|
|
7
|
+
data.tar.gz: 211b4d9ed455e19688bbb29acc7beb5043150703e144bb38f973b68f6bbf5fb3aa942c7fd2d77faa4332df243cb5f0d50e4a06813c7786b7c954f5a8eb674900
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.1] - 2026-02-16
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Replace raw arrays and hashes with FiberProtocol Data classes for typed protocol messages ([#175](https://github.com/ahogappa/taski/pull/175))
|
|
14
|
+
- Add AST-guided start_dep speculative parallel execution for improved performance ([#175](https://github.com/ahogappa/taski/pull/175))
|
|
15
|
+
- Add TaskProxy for lazy dependency resolution with unsafe proxy usage detection ([#175](https://github.com/ahogappa/taski/pull/175))
|
|
16
|
+
- Remove static-graph-based task scheduling from Executor in favor of Fiber pull model ([#176](https://github.com/ahogappa/taski/pull/176))
|
|
17
|
+
- Replace inline `Class.new(Taski::Task)` with named fixture classes in tests ([#174](https://github.com/ahogappa/taski/pull/174))
|
|
18
|
+
- Add custom export methods section to README ([#172](https://github.com/ahogappa/taski/pull/172))
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- Fix data race on `@next_thread_index` in enqueue/enqueue_clean ([#175](https://github.com/ahogappa/taski/pull/175))
|
|
22
|
+
|
|
23
|
+
## [0.9.0] - 2026-02-08
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Fiber-based lazy dependency resolution replacing Monitor-based approach ([#157](https://github.com/ahogappa/taski/pull/157))
|
|
27
|
+
- Layout/Theme architecture for progress display ([#150](https://github.com/ahogappa/taski/pull/150))
|
|
28
|
+
- Layout::Tree for hierarchical task display with TTY/non-TTY dual mode ([#151](https://github.com/ahogappa/taski/pull/151))
|
|
29
|
+
- Structured logging support for debugging and monitoring ([#141](https://github.com/ahogappa/taski/pull/141))
|
|
30
|
+
- Skipped task reporting in progress display and logging ([#157](https://github.com/ahogappa/taski/pull/157))
|
|
31
|
+
- `clean_on_failure` option for `run_and_clean` ([#169](https://github.com/ahogappa/taski/pull/169))
|
|
32
|
+
- `short_name` filter for template name formatting ([#151](https://github.com/ahogappa/taski/pull/151))
|
|
33
|
+
- TaskDrop and ExecutionDrop for structured template variables ([#151](https://github.com/ahogappa/taski/pull/151))
|
|
34
|
+
- Group duration computation in Layout::Base ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
35
|
+
- `mark_clean_failed` in Scheduler for symmetric failure tracking ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
36
|
+
- Ruby 4.0 support in CI ([#160](https://github.com/ahogappa/taski/pull/160))
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- Replace ExecutionContext with ExecutionFacade/TaskObserver architecture ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
40
|
+
- Remove SharedState, unify task state in TaskWrapper ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
41
|
+
- Remove Section API in favor of simple if-statement selection (BREAKING) ([#157](https://github.com/ahogappa/taski/pull/157))
|
|
42
|
+
- Simplify clean API by removing `Task.clean` and `Task.new` (BREAKING) ([#163](https://github.com/ahogappa/taski/pull/163))
|
|
43
|
+
- Simplify progress display configuration to single setter API ([#161](https://github.com/ahogappa/taski/pull/161))
|
|
44
|
+
- Rename `completed?`/`clean_completed?` to `finished?`/`clean_finished?` (BREAKING) ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
45
|
+
- Unify `STATE_ERROR` to `STATE_FAILED` across execution layer (BREAKING) ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
46
|
+
- Rename Template to Theme, Layout::Plain to Layout::Log ([#151](https://github.com/ahogappa/taski/pull/151))
|
|
47
|
+
- Rename `execution_context` to `execution_facade` across codebase ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
48
|
+
- Merge FiberExecutor into Executor, rename FiberWorkerPool to WorkerPool ([#157](https://github.com/ahogappa/taski/pull/157))
|
|
49
|
+
- Replace inline `Class.new(Taski::Task)` with named fixture classes in tests ([#166](https://github.com/ahogappa/taski/pull/166))
|
|
50
|
+
- Drop Ruby 3.2 from CI ([#160](https://github.com/ahogappa/taski/pull/160))
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- Recursively add transitive dependencies in `merge_runtime_dependencies` ([#142](https://github.com/ahogappa/taski/pull/142))
|
|
54
|
+
- Handle `Errno::EBADF` in TaskOutputRouter pipe operations ([#159](https://github.com/ahogappa/taski/pull/159))
|
|
55
|
+
- Truncate simple progress line to terminal width ([#152](https://github.com/ahogappa/taski/pull/152))
|
|
56
|
+
- Improve thread safety in Registry and WorkerPool ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
57
|
+
- Restore fiber context on resume, scope output capture per-fiber ([#157](https://github.com/ahogappa/taski/pull/157))
|
|
58
|
+
- Prevent duplicate `:start` responses and ensure observer event ordering ([#157](https://github.com/ahogappa/taski/pull/157))
|
|
59
|
+
- Route observer errors through structured logger instead of `warn` ([#167](https://github.com/ahogappa/taski/pull/167))
|
|
60
|
+
- Resolve Bundler permission error on Ruby 4.0 CI ([#162](https://github.com/ahogappa/taski/pull/162))
|
|
61
|
+
|
|
10
62
|
## [0.8.3] - 2026-01-26
|
|
11
63
|
|
|
12
64
|
### Fixed
|
data/README.md
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
- **Automatic Dependency Resolution**: Dependencies detected via static analysis
|
|
14
14
|
- **Parallel Execution**: Independent tasks run concurrently for maximum performance
|
|
15
|
-
- **
|
|
15
|
+
- **Exports API**: Simple value sharing between tasks
|
|
16
16
|
- **Real-time Progress**: Visual feedback with parallel task progress display
|
|
17
|
-
- **
|
|
17
|
+
- **Fiber-Based Execution**: Lightweight Fiber-based dependency resolution for efficient parallel execution
|
|
18
|
+
- **Lazy Dependency Resolution**: Dependencies return lightweight proxies that defer resolution until the value is actually used, enabling better parallelism
|
|
18
19
|
|
|
19
20
|
## Quick Start
|
|
20
21
|
|
|
@@ -77,42 +78,72 @@ class Server < Taski::Task
|
|
|
77
78
|
end
|
|
78
79
|
```
|
|
79
80
|
|
|
80
|
-
###
|
|
81
|
+
### Custom Export Methods
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
By default, `exports` generates a reader that returns the instance variable (e.g., `exports :value` reads `@value`). You can override this by defining your own instance method with the same name:
|
|
84
|
+
|
|
85
|
+
**Fixed values** — no computation needed in `run`:
|
|
83
86
|
|
|
84
87
|
```ruby
|
|
85
|
-
class
|
|
86
|
-
|
|
88
|
+
class Config < Taski::Task
|
|
89
|
+
exports :timeout
|
|
87
90
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
def timeout
|
|
92
|
+
30
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def run; end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
Config.timeout # => 30
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Shared logic between `run` and `clean`** — the method works as both an export and a regular instance method:
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
class DatabaseSetup < Taski::Task
|
|
105
|
+
exports :connection
|
|
106
|
+
|
|
107
|
+
def connection
|
|
108
|
+
@connection ||= Database.connect
|
|
93
109
|
end
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
111
|
+
def run
|
|
112
|
+
connection.setup_schema
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def clean
|
|
116
|
+
connection.close
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Conditional Logic - Runtime Selection
|
|
122
|
+
|
|
123
|
+
Use `if` statements to switch behavior based on environment:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
class DatabaseConfig < Taski::Task
|
|
127
|
+
exports :host, :port
|
|
128
|
+
|
|
129
|
+
def run
|
|
130
|
+
if ENV['RAILS_ENV'] == 'production'
|
|
131
|
+
@host = "prod.example.com"
|
|
132
|
+
@port = 5432
|
|
133
|
+
else
|
|
97
134
|
@host = "localhost"
|
|
98
135
|
@port = 5432
|
|
99
136
|
end
|
|
100
137
|
end
|
|
101
|
-
|
|
102
|
-
def impl
|
|
103
|
-
ENV['RAILS_ENV'] == 'production' ? Production : Development
|
|
104
|
-
end
|
|
105
138
|
end
|
|
106
139
|
|
|
107
140
|
class App < Taski::Task
|
|
108
141
|
def run
|
|
109
|
-
puts "Connecting to #{
|
|
142
|
+
puts "Connecting to #{DatabaseConfig.host}:#{DatabaseConfig.port}"
|
|
110
143
|
end
|
|
111
144
|
end
|
|
112
145
|
```
|
|
113
146
|
|
|
114
|
-
> **Note**: Nested implementation classes automatically inherit Section's `interfaces` as `exports`.
|
|
115
|
-
|
|
116
147
|
## Best Practices
|
|
117
148
|
|
|
118
149
|
### Keep Tasks Small and Focused
|
|
@@ -236,16 +267,49 @@ Env API (execution environment):
|
|
|
236
267
|
RandomTask.value # => 42
|
|
237
268
|
RandomTask.value # => 99 (different value - fresh execution)
|
|
238
269
|
|
|
239
|
-
# Instance-level caching
|
|
240
|
-
instance = RandomTask.new
|
|
241
|
-
instance.run # => 42
|
|
242
|
-
instance.run # => 42 (cached within instance)
|
|
243
|
-
instance.value # => 42
|
|
244
|
-
|
|
245
270
|
# Dependencies within same execution share results
|
|
246
271
|
DoubleConsumer.run # RandomTask runs once, both accesses get same value
|
|
247
272
|
```
|
|
248
273
|
|
|
274
|
+
When a task accesses a dependency (e.g., `SomeDep.value`), the result may be a lightweight proxy. The actual resolution is deferred until the value is used, allowing independent dependencies to execute in parallel transparently. This is automatic and requires no changes to your task code. Dependencies used in conditions or as arguments are automatically resolved synchronously for safety.
|
|
275
|
+
|
|
276
|
+
### Error Handling
|
|
277
|
+
|
|
278
|
+
When a task fails, Taski wraps the error with task-specific context. Each task class automatically gets a `::Error` subclass for targeted rescue:
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
class FetchData < Taski::Task
|
|
282
|
+
exports :data
|
|
283
|
+
def run
|
|
284
|
+
@data = API.fetch # may raise
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
class ProcessData < Taski::Task
|
|
289
|
+
def run
|
|
290
|
+
FetchData.data
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Rescue a specific task's error
|
|
295
|
+
begin
|
|
296
|
+
ProcessData.run
|
|
297
|
+
rescue FetchData::Error => e
|
|
298
|
+
puts "FetchData failed: #{e.cause.message}"
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Rescue all task failures with AggregateError
|
|
302
|
+
begin
|
|
303
|
+
ProcessData.run
|
|
304
|
+
rescue Taski::AggregateError => e
|
|
305
|
+
e.errors.each do |failure|
|
|
306
|
+
puts "#{failure.task_class}: #{failure.error.message}"
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`AggregateError` collects all failures from parallel execution. Task-specific `::Error` classes work transparently with `rescue` — even when errors are wrapped inside an `AggregateError`.
|
|
312
|
+
|
|
249
313
|
### Aborting Execution
|
|
250
314
|
|
|
251
315
|
Stop all pending tasks when a critical error occurs:
|
|
@@ -282,17 +346,24 @@ end
|
|
|
282
346
|
# Run then clean in one call
|
|
283
347
|
DatabaseSetup.run_and_clean
|
|
284
348
|
|
|
285
|
-
#
|
|
286
|
-
DatabaseSetup.
|
|
287
|
-
|
|
288
|
-
|
|
349
|
+
# Run, do something with exported values, then clean
|
|
350
|
+
DatabaseSetup.run_and_clean do
|
|
351
|
+
deploy(DatabaseSetup.connection)
|
|
352
|
+
end
|
|
289
353
|
```
|
|
290
354
|
|
|
291
|
-
See [docs/
|
|
355
|
+
See [docs/GUIDE.md](docs/GUIDE.md#lifecycle-management) for details.
|
|
292
356
|
|
|
293
357
|
### Progress Display
|
|
294
358
|
|
|
295
|
-
|
|
359
|
+
Simple progress display is enabled by default:
|
|
360
|
+
|
|
361
|
+
```text
|
|
362
|
+
⠹ [3/5] DeployTask | Uploading files...
|
|
363
|
+
✓ [5/5] All tasks completed (1234ms)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Tree mode** provides full dependency tree visualization:
|
|
296
367
|
|
|
297
368
|
```
|
|
298
369
|
WebServer (Task)
|
|
@@ -302,14 +373,7 @@ WebServer (Task)
|
|
|
302
373
|
└── ◻ Server (Task)
|
|
303
374
|
```
|
|
304
375
|
|
|
305
|
-
**
|
|
306
|
-
|
|
307
|
-
```
|
|
308
|
-
⠹ [3/5] DeployTask | Uploading files...
|
|
309
|
-
✓ [5/5] All tasks completed (1234ms)
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Plain mode** provides text output without escape codes (for CI/logs):
|
|
376
|
+
**Log mode** provides text output without escape codes (for CI/logs):
|
|
313
377
|
|
|
314
378
|
```
|
|
315
379
|
[START] DatabaseSetup
|
|
@@ -322,18 +386,12 @@ WebServer (Task)
|
|
|
322
386
|
**Configuration:**
|
|
323
387
|
|
|
324
388
|
```ruby
|
|
325
|
-
#
|
|
326
|
-
Taski.
|
|
327
|
-
Taski.
|
|
328
|
-
Taski.
|
|
329
|
-
|
|
330
|
-
# Via environment variable
|
|
331
|
-
TASKI_PROGRESS_MODE=simple ruby your_script.rb
|
|
332
|
-
TASKI_PROGRESS_MODE=plain ruby your_script.rb
|
|
389
|
+
Taski.progress_display = Taski::Progress::Layout::Simple.new # Simple display (default)
|
|
390
|
+
Taski.progress_display = Taski::Progress::Layout::Tree.new # Tree display
|
|
391
|
+
Taski.progress_display = Taski::Progress::Layout::Log.new # Log output (CI/logs)
|
|
392
|
+
Taski.progress_display = nil # Disable
|
|
333
393
|
```
|
|
334
394
|
|
|
335
|
-
To disable: `TASKI_PROGRESS_DISABLE=1 ruby your_script.rb`
|
|
336
|
-
|
|
337
395
|
### Tree Visualization
|
|
338
396
|
|
|
339
397
|
```ruby
|
data/docs/GUIDE.md
CHANGED
|
@@ -7,6 +7,7 @@ This guide provides detailed documentation beyond the basics covered in the READ
|
|
|
7
7
|
- [Error Handling](#error-handling)
|
|
8
8
|
- [Lifecycle Management](#lifecycle-management)
|
|
9
9
|
- [Progress Display](#progress-display)
|
|
10
|
+
- [Lazy Dependency Resolution](#lazy-dependency-resolution)
|
|
10
11
|
- [Debugging](#debugging)
|
|
11
12
|
|
|
12
13
|
---
|
|
@@ -87,7 +88,9 @@ rescue DatabaseTask::Error => e
|
|
|
87
88
|
end
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
This works transparently with `AggregateError`
|
|
91
|
+
This works transparently with `AggregateError` — when you rescue `DatabaseTask::Error`, it matches an `AggregateError` that contains a `DatabaseTask::Error`.
|
|
92
|
+
|
|
93
|
+
**How this works:** Ruby's `rescue` uses the `===` operator to match exceptions. Taski's `AggregateAware` module (extended by `TaskError` and all `TaskClass::Error` classes) overrides `===` to check whether an `AggregateError` *contains* an error of that type. This means `rescue Taski::TaskError` will match an `AggregateError` wrapping TaskError instances, even though `AggregateError` does not inherit from `TaskError`.
|
|
91
94
|
|
|
92
95
|
### TaskAbortException
|
|
93
96
|
|
|
@@ -140,7 +143,7 @@ end
|
|
|
140
143
|
|
|
141
144
|
## Lifecycle Management
|
|
142
145
|
|
|
143
|
-
Taski supports resource cleanup with `
|
|
146
|
+
Taski supports resource cleanup with `run_and_clean`, which executes the run phase followed by the clean phase in a single operation.
|
|
144
147
|
|
|
145
148
|
### Basic Lifecycle
|
|
146
149
|
|
|
@@ -168,27 +171,24 @@ class WebServer < Taski::Task
|
|
|
168
171
|
end
|
|
169
172
|
end
|
|
170
173
|
|
|
171
|
-
#
|
|
172
|
-
WebServer.
|
|
174
|
+
# Run then clean in one call
|
|
175
|
+
WebServer.run_and_clean
|
|
173
176
|
# => Database connected
|
|
174
|
-
# => Server started
|
|
175
|
-
|
|
176
|
-
# Clean (reverse dependency order)
|
|
177
|
-
WebServer.clean
|
|
177
|
+
# => Server started
|
|
178
178
|
# => Server stopped
|
|
179
179
|
# => Database disconnected
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
### run_and_clean
|
|
182
|
+
### run_and_clean with Block
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
Use a block to execute code between run and clean phases. This is useful when you need to use exported values before cleanup:
|
|
185
185
|
|
|
186
186
|
```ruby
|
|
187
|
-
|
|
188
|
-
#
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
#
|
|
187
|
+
DatabaseSetup.run_and_clean do
|
|
188
|
+
# Exported values are accessible here
|
|
189
|
+
deploy(DatabaseSetup.connection)
|
|
190
|
+
end
|
|
191
|
+
# Clean runs automatically after the block
|
|
192
192
|
```
|
|
193
193
|
|
|
194
194
|
### Idempotent Clean Methods
|
|
@@ -289,21 +289,9 @@ After completion:
|
|
|
289
289
|
|
|
290
290
|
### Display Modes
|
|
291
291
|
|
|
292
|
-
Taski supports
|
|
292
|
+
Taski supports three progress display modes:
|
|
293
293
|
|
|
294
|
-
####
|
|
295
|
-
|
|
296
|
-
Full dependency tree visualization with status for each task:
|
|
297
|
-
|
|
298
|
-
```
|
|
299
|
-
WebServer (Task)
|
|
300
|
-
├── ⠋ Config (Task) | Reading config.yml...
|
|
301
|
-
│ ├── ✅ Database (Task) 45.2ms
|
|
302
|
-
│ └── ⠙ Cache (Task) | Connecting...
|
|
303
|
-
└── ◻ Server (Task)
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
#### Simple Mode
|
|
294
|
+
#### Simple Mode (Default)
|
|
307
295
|
|
|
308
296
|
Compact single-line display showing current progress:
|
|
309
297
|
|
|
@@ -324,7 +312,19 @@ On failure:
|
|
|
324
312
|
✗ [3/5] DeployTask failed: Connection refused
|
|
325
313
|
```
|
|
326
314
|
|
|
327
|
-
####
|
|
315
|
+
#### Tree Mode
|
|
316
|
+
|
|
317
|
+
Full dependency tree visualization with status for each task:
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
WebServer (Task)
|
|
321
|
+
├── ⠋ Config (Task) | Reading config.yml...
|
|
322
|
+
│ ├── ✅ Database (Task) 45.2ms
|
|
323
|
+
│ └── ⠙ Cache (Task) | Connecting...
|
|
324
|
+
└── ◻ Server (Task)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
#### Log Mode
|
|
328
328
|
|
|
329
329
|
Plain text output without escape codes, designed for CI/logs:
|
|
330
330
|
|
|
@@ -336,49 +336,73 @@ Plain text output without escape codes, designed for CI/logs:
|
|
|
336
336
|
[TASKI] Completed: 2/2 tasks (165ms)
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
### Configuring Progress
|
|
340
|
-
|
|
341
|
-
**Via API:**
|
|
339
|
+
### Configuring Progress Display
|
|
342
340
|
|
|
343
341
|
```ruby
|
|
344
|
-
Taski.
|
|
345
|
-
Taski.
|
|
346
|
-
Taski.
|
|
342
|
+
Taski.progress_display = Taski::Progress::Layout::Simple.new # Simple display (default)
|
|
343
|
+
Taski.progress_display = Taski::Progress::Layout::Tree.new # Tree display
|
|
344
|
+
Taski.progress_display = Taski::Progress::Layout::Log.new # Log output (CI/logs)
|
|
345
|
+
Taski.progress_display = nil # Disable
|
|
347
346
|
```
|
|
348
347
|
|
|
349
|
-
|
|
348
|
+
### File Output Mode
|
|
349
|
+
|
|
350
|
+
When output is redirected, interactive spinners are automatically disabled:
|
|
350
351
|
|
|
351
352
|
```bash
|
|
352
|
-
|
|
353
|
-
TASKI_PROGRESS_MODE=simple ruby your_script.rb
|
|
354
|
-
TASKI_PROGRESS_MODE=plain ruby your_script.rb
|
|
353
|
+
ruby build.rb > build.log 2>&1
|
|
355
354
|
```
|
|
356
355
|
|
|
357
|
-
|
|
356
|
+
---
|
|
358
357
|
|
|
359
|
-
|
|
360
|
-
TASKI_PROGRESS_DISABLE=1 ruby your_script.rb
|
|
361
|
-
```
|
|
358
|
+
## Lazy Dependency Resolution
|
|
362
359
|
|
|
363
|
-
###
|
|
360
|
+
### How It Works
|
|
364
361
|
|
|
365
|
-
When
|
|
362
|
+
When a task accesses a dependency's exported value (e.g., `DepTask.value`), Taski may return a lightweight **proxy object** instead of the actual value. This proxy defers dependency resolution until you call a method on it, at which point it transparently resolves the real value and forwards the method call.
|
|
366
363
|
|
|
367
|
-
```
|
|
368
|
-
|
|
364
|
+
```ruby
|
|
365
|
+
class FetchData < Taski::Task
|
|
366
|
+
exports :data
|
|
367
|
+
def run
|
|
368
|
+
@data = expensive_api_call
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
class ProcessData < Taski::Task
|
|
373
|
+
exports :result
|
|
374
|
+
def run
|
|
375
|
+
raw = FetchData.data # May return a proxy (no blocking yet)
|
|
376
|
+
setup_environment # Task continues while FetchData runs
|
|
377
|
+
@result = raw.transform # Proxy resolves here — blocks if needed
|
|
378
|
+
end
|
|
379
|
+
end
|
|
369
380
|
```
|
|
370
381
|
|
|
382
|
+
From the user's perspective, the proxy is completely transparent — it behaves exactly like the real value.
|
|
383
|
+
|
|
384
|
+
### Why It Matters
|
|
385
|
+
|
|
386
|
+
Proxy-based resolution enables better parallelism. A task can continue executing setup logic while its dependencies are still running, only blocking when the dependency value is actually used. This can significantly reduce total execution time when tasks have independent setup work before they need their dependencies.
|
|
387
|
+
|
|
388
|
+
### Automatic Safety
|
|
389
|
+
|
|
390
|
+
Taski uses static analysis (Prism AST parsing) to determine when proxy resolution is safe. Dependencies used in positions where the proxy could cause issues — such as conditions (`if dep_value`), method arguments, or other contexts where truthiness or identity matters — are automatically resolved synchronously instead of returning a proxy.
|
|
391
|
+
|
|
392
|
+
You do not need to think about this in normal usage. The static analyzer examines your task's `run` method and only enables proxy resolution for dependency accesses that are confirmed safe (e.g., simple assignments like `x = Dep.value` followed by method calls on `x`).
|
|
393
|
+
|
|
371
394
|
---
|
|
372
395
|
|
|
373
396
|
## Debugging
|
|
374
397
|
|
|
375
|
-
###
|
|
398
|
+
### Structured Logging
|
|
399
|
+
|
|
400
|
+
```ruby
|
|
401
|
+
require "logger"
|
|
402
|
+
Taski.logger = Logger.new($stdout, level: Logger::DEBUG)
|
|
403
|
+
```
|
|
376
404
|
|
|
377
|
-
|
|
378
|
-
|----------|---------|
|
|
379
|
-
| `TASKI_PROGRESS_DISABLE=1` | Disable progress display |
|
|
380
|
-
| `TASKI_PROGRESS_MODE=tree\|simple\|plain` | Set progress display mode (default: tree) |
|
|
381
|
-
| `TASKI_DEBUG=1` | Enable debug output |
|
|
405
|
+
Set `Taski.logger` to a Ruby `Logger` instance to enable structured logging of execution events.
|
|
382
406
|
|
|
383
407
|
### Dependency Tree Visualization
|
|
384
408
|
|
|
@@ -405,4 +429,4 @@ end
|
|
|
405
429
|
|
|
406
430
|
**Static Analysis Requirements**
|
|
407
431
|
|
|
408
|
-
Tasks must be defined in source files (not dynamically with `Class.new`) because static analysis uses Prism AST parsing which requires actual source files.
|
|
432
|
+
Tasks must be defined in source files (not dynamically with `Class.new`) because static analysis uses Prism AST parsing which requires actual source files. Static analysis is used for dependency tree visualization, circular dependency detection, and optimizing dependency resolution (determining when lazy proxy resolution is safe vs. when synchronous resolution is required).
|
data/examples/README.md
CHANGED
|
@@ -19,22 +19,7 @@ ruby examples/quick_start.rb
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
### 2.
|
|
23
|
-
|
|
24
|
-
Switch implementations based on environment using the Section API.
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
ruby examples/section_demo.rb
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Covers:**
|
|
31
|
-
- `interfaces` for defining contracts
|
|
32
|
-
- Environment-specific implementations
|
|
33
|
-
- Dependency tree visualization with `.tree`
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
### 3. args_demo.rb - Runtime Args and Options
|
|
22
|
+
### 2. args_demo.rb - Runtime Args and Options
|
|
38
23
|
|
|
39
24
|
Access execution args and pass custom options to tasks.
|
|
40
25
|
|
|
@@ -52,22 +37,21 @@ ruby examples/args_demo.rb
|
|
|
52
37
|
|
|
53
38
|
---
|
|
54
39
|
|
|
55
|
-
###
|
|
40
|
+
### 3. reexecution_demo.rb - Scope-Based Execution
|
|
56
41
|
|
|
57
42
|
Understand scope-based execution and caching behavior.
|
|
58
43
|
|
|
59
44
|
```bash
|
|
60
|
-
|
|
45
|
+
ruby examples/reexecution_demo.rb
|
|
61
46
|
```
|
|
62
47
|
|
|
63
48
|
**Covers:**
|
|
64
49
|
- Fresh execution for each class method call
|
|
65
|
-
- Instance-level caching with `Task.new`
|
|
66
50
|
- Scope-based dependency caching
|
|
67
51
|
|
|
68
52
|
---
|
|
69
53
|
|
|
70
|
-
###
|
|
54
|
+
### 4. clean_demo.rb - Lifecycle Management
|
|
71
55
|
|
|
72
56
|
Demonstrates resource cleanup with clean methods.
|
|
73
57
|
|
|
@@ -79,10 +63,11 @@ ruby examples/clean_demo.rb
|
|
|
79
63
|
- Defining `clean` methods for resource cleanup
|
|
80
64
|
- Reverse dependency order execution
|
|
81
65
|
- `run_and_clean` combined operation
|
|
66
|
+
- `run_and_clean` with block support
|
|
82
67
|
|
|
83
68
|
---
|
|
84
69
|
|
|
85
|
-
###
|
|
70
|
+
### 5. group_demo.rb - Task Output Grouping
|
|
86
71
|
|
|
87
72
|
Organize task output into logical phases with groups.
|
|
88
73
|
|
|
@@ -97,7 +82,7 @@ ruby examples/group_demo.rb
|
|
|
97
82
|
|
|
98
83
|
---
|
|
99
84
|
|
|
100
|
-
###
|
|
85
|
+
### 6. message_demo.rb - User-Facing Messages
|
|
101
86
|
|
|
102
87
|
Output messages that bypass the progress display capture.
|
|
103
88
|
|
|
@@ -112,14 +97,12 @@ ruby examples/message_demo.rb
|
|
|
112
97
|
|
|
113
98
|
---
|
|
114
99
|
|
|
115
|
-
###
|
|
100
|
+
### 7. progress_demo.rb - Progress Display Modes
|
|
116
101
|
|
|
117
102
|
Real-time progress visualization during parallel execution.
|
|
118
103
|
|
|
119
104
|
```bash
|
|
120
|
-
ruby examples/progress_demo.rb
|
|
121
|
-
TASKI_PROGRESS_MODE=simple ruby examples/progress_demo.rb # Simple mode
|
|
122
|
-
TASKI_PROGRESS_DISABLE=1 ruby examples/progress_demo.rb # Disabled
|
|
105
|
+
ruby examples/progress_demo.rb # Simple mode (default)
|
|
123
106
|
```
|
|
124
107
|
|
|
125
108
|
**Covers:**
|
|
@@ -136,7 +119,6 @@ TASKI_PROGRESS_DISABLE=1 ruby examples/progress_demo.rb # Disabled
|
|
|
136
119
|
| Example | Feature | Complexity |
|
|
137
120
|
|---------|---------|------------|
|
|
138
121
|
| quick_start | Exports API | Basic |
|
|
139
|
-
| section_demo | Section API | Intermediate |
|
|
140
122
|
| args_demo | Args/Env API | Intermediate |
|
|
141
123
|
| reexecution_demo | Scope-Based Execution | Intermediate |
|
|
142
124
|
| clean_demo | Lifecycle Management | Intermediate |
|
|
@@ -150,8 +132,7 @@ TASKI_PROGRESS_DISABLE=1 ruby examples/progress_demo.rb # Disabled
|
|
|
150
132
|
# Run each example
|
|
151
133
|
for f in examples/*.rb; do echo "=== $f ===" && ruby "$f" && echo; done
|
|
152
134
|
|
|
153
|
-
# Disable progress display if needed
|
|
154
|
-
TASKI_PROGRESS_DISABLE=1 ruby examples/progress_demo.rb
|
|
135
|
+
# Disable progress display if needed (add Taski.progress_display = nil in script)
|
|
155
136
|
```
|
|
156
137
|
|
|
157
138
|
## Next Steps
|