视频课程目录16
全部视频课程

13 · HHY 1.7.0

Watch Files and Schedule Work

Trigger a local build from one file event and stop a timer after three ticks.

4:51 · 英文旁白与字幕

学习进度保存在此浏览器,无需登录。

阅读对应手册章节

章节与讲稿

点击时间跳转视频,展开标题查看讲稿与代码。

Automation needs an ending

A watcher reacts to changes, while a timer schedules work at intervals. Both are useful for automation, and both naturally keep running. In this lesson we will make their lifetime explicit. First, a timer prints exactly three ticks. Then a file event triggers one small local build and the watcher exits. These bounded demonstrations are easier to test and understand than an unattended background process, and they give us a clear result to verify at the end.

hhy
tick
tick
tick
done

Actual output from ticks.hhy.

Bound a timer before consuming it

Every creates a stream of timer ticks. Here the interval is one hundred milliseconds, which keeps the demonstration quick. Take limits the stream to three values before for each consumes it. Each tick prints the same short label, and the final line proves that execution continued after the stream ended. The timer interval is not a precise real time scheduling guarantee. If downstream work takes time, the pipeline follows backpressure rather than promising overlapping executions for every clock interval.

hhy
every(100ms) |> take(3)
    |> for_each { tick -> print("tick") }
print("done")

Run hhy run ticks.hhy.

See an unbounded barrier fail

Now run the unbounded example. Collect needs the entire input before it can return a list, but an unlimited timer never supplies a final item. HHY rejects this with a plan error telling us to apply a bound. The fix is about the lifetime of the data, not about adding more memory or waiting longer. Put take before a collecting, sorting, or grouping barrier whenever your source is naturally infinite and your task requires a finite result.

hhy
every(100ms) |> collect |> print

unbounded.hhy intentionally produces PlanError.

Create the file watcher

Our watcher observes the fixtures directory recursively. Debounce reduces rapid repeated events, and take limits this demonstration to one accepted event. The documentation describes leading edge behavior: the first event is emitted immediately, and repeated events with the same key are coalesced during the window. It is not a promise to wait for every editor to finish writing. For this lesson, we create a separate trigger file only after our source content is ready, making the build input deliberate and reproducible.

hhy
watch(path("fixtures"), { recursive: true })
    |> debounce(300ms)
    |> take(1)

Watch-build waits for one accepted event.

Run a bounded build command

Inside the event handler, run invokes the supplied Python build script with a two second timeout. The build reads source dot text and prints its contents with a built label. This is deliberately small so the lesson stays focused on orchestration. A nonzero process exit code needs an explicit decision: here we print standard error, while success prints standard output. You can later substitute your real build command without changing the basic event, process, and result handling structure.

hhy
let result = run(["python3", "build.py"], { timeout: 2s })
if result.exit_code != 0 { print_error(result.stderr) }
else { print(result.stdout) }

This block runs inside the event handler.

Trigger once, then stop

Start the watcher from the examples directory, then create the trigger file in another terminal. You should see change detected, the build output, and watch complete. The included verification driver performs this sequence and cleans up its trigger file. Filesystem event delivery varies by platform and editor. In our local validation, creating a file triggered reliably, while rewriting an existing file did not. That is why this demonstration uses a creation event and does not promise identical save behavior on every system.

Terminal
hhy run watch-build.hhy
# In another terminal, create fixtures/trigger.txt

Use verify.py for a fully bounded automated demonstration.

Choose event and lifecycle policies

For a longer running tool, decide which event kinds should trigger work and which files should be ignored. Writing generated output into the watched source directory can cause an unwanted loop. Keep the outputs elsewhere and filter according to your actual build inputs. During this tutorial, take gives us a normal finish. If no event arrives, Control C stops the watcher; the verification driver also has an outer timeout so an unexpected platform issue cannot leave the test waiting indefinitely.

hhy
created · modified · removed · renamed
Normal finish: take(1)
Manual stop: Control C

Keep generated outputs outside the watched source directory.

Practice a controlled workflow

For practice, update source dot text, start a fresh watcher, and create the trigger file again. Predict the build output before you run the sequence. Then change the timer example to five ticks and verify that done still appears exactly once. Keep these two sources separate until their lifetimes feel familiar. You can now schedule finite work and respond to a filesystem signal with an explicit stopping condition. In the next lesson, we will combine several earlier techniques into a real log report.

hhy
Source ready  create trigger  build  exit

Exercise: change source.txt, then trigger another fresh run.