Last active
November 7, 2023 17:12
-
-
Save cowboyd/0611f51cbe8b834b408c40c54d98064d to your computer and use it in GitHub Desktop.
Run an operation on a heartbeat, only one operation at a time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
call, | |
createSignal, | |
each, | |
type Operation, | |
spawn, | |
type Stream, | |
suspend, | |
} from "effection"; | |
/** | |
* Create an infinite stream of pulses that happen on the given period. | |
*/ | |
export function pulse(period: number): Stream<void, never> { | |
return { | |
*subscribe() { | |
let signal = createSignal<void, never>(); | |
yield* spawn(function* () { | |
let intervalId = setInterval(signal.send, period); | |
try { | |
yield* suspend(); | |
} finally { | |
clearInterval(intervalId); | |
} | |
}); | |
return yield* signal.subscribe(); | |
}, | |
}; | |
} | |
/** | |
* Run an operation on a heartbeat loop. | |
* For each tick of the loop, spawn the operation and await the next tick. | |
* If the next pulse happens while the spawned operation is still running, it will be shut | |
* down because it passes out of scope when the `call()` returns. | |
*/ | |
export function* heartbeat(period: number, operation: () => Operation<unknown>): Operation<void> { | |
for (let _ of yield* each(pulse(period))) { | |
yield* call(function* () { | |
yield* spawn(operation); | |
yield* each.next(); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment