Skip to content

Instantly share code, notes, and snippets.

@cowboyd cowboyd/timebox.js
Last active Jul 29, 2019

Embed
What would you like to do?
Structured timeouts
import { timeout } from 'effection';
/**
* Run a process in a timebox. In other words, if the
* process does not complete within the specified time
* period, throw a timeout error.
*/
export function timebox(durationMillis, proc) {
return function*() {
// fork the process
let process = this.fork(proc);
// wait for the timeout period
yield timeout(durationMillis);
if (process.isCompleted) {
// yay! we're finished, return the result.
return process.result;
} else {
// the process is still running, so raise an error.
// the fact that it's parent process (the timebox) is erroring
// out will mean that the forked child will be automatically
// halted. Simple and clean!
let error = new Error('timeout period exceeded');
error.name = 'TimeoutError';
throw error;
}
};
}
// example usage:
import ble from '~system/ble';
export function* connectToPeripheral(id) {
return yield timebox(5000, function*() {
ble.connect(id);
let event = yield untilEvent(ble, 'connect', e => e.deviceId === id);
return event.target;
});
}
/**
* An execution controller that resumes computation once an event
* emmitter emits a matching event.
*/
export function untilEvent(emitter, eventName, match = () => true) {
return function control(execution) {
function handle(event) {
if (match(event)) {
execution.resume(event);
}
}
// install the event listener
emitter.on(eventName, handle);
// always remove the event listener when this passes out of scope.
return () => emitter.off(eventName, handle);
};
}
import { timebox } from './timebox';
import { untilEvent } from './untilEvent';
import { ble } from '~/system/ble';
// we can now model our connection process and the associated timeouts and retries
// very cleanly.
export function* connectToPeripheral(id) {
retry:
try {
return yield timebox(5000, function*() {
ble.connect(id);
let event = yield untilEvent(ble, 'connect', e => e.deviceId === id);
return event.target;
});
} catch (error) {
if (confirm(`error connecting to device: ${error.message}. Try again+?`)) {
break retry;
} else {
throw error;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.