Skip to content

Commit

Permalink
chore: add listener error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
FaberVitale committed Nov 8, 2021
1 parent 22418fe commit e2b9b1c
Showing 1 changed file with 56 additions and 5 deletions.
61 changes: 56 additions & 5 deletions packages/action-listener-middleware/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ export type ActionListener<
O extends ActionListenerOptions
> = (action: A, api: ActionListenerMiddlewareAPI<S, D, O>) => void

export interface ListenerErrorHandler {
(error: unknown): void
}

export interface ActionListenerOptions {
/**
* Determines if the listener runs 'before' or 'after' the reducers have been called.
Expand All @@ -105,6 +109,7 @@ export interface ActionListenerOptions {

export interface CreateListenerMiddlewareOptions<ExtraArgument = unknown> {
extra?: ExtraArgument
onError?: ListenerErrorHandler
}

export interface AddListenerAction<
Expand All @@ -121,6 +126,37 @@ export interface AddListenerAction<
}
}

/**
* Safely reports errors to the `errorHandler` provided.
* Errors that occur inside `errorHandler` are notified in a new task.
* Inspired by [rxjs reportUnhandledError](https://github.com/ReactiveX/rxjs/blob/6fafcf53dc9e557439b25debaeadfd224b245a66/src/internal/util/reportUnhandledError.ts)
* @param errorHandler
* @param errorToNotify
*/
const safelyNotifyError = (
errorHandler: ListenerErrorHandler,
errorToNotify: unknown
): void => {
try {
errorHandler(errorToNotify)
} catch (errorHandlerError) {
// We cannot let an error raised here block the listener queue.
// The error raised here will be picked up by `window.onerror`, `process.on('error')` etc...
setTimeout(() => {
throw errorHandlerError
}, 0)
}
}

const assertFunction = (
func: unknown,
expected: string
): asserts func is (...args: unknown[]) => unknown => {
if (typeof func !== 'function') {
throw new TypeError(`${expected} in not a function`)
}
}

/**
* @alpha
*/
Expand Down Expand Up @@ -220,6 +256,9 @@ export const removeListenerAction = createAction(

const defaultWhen: MiddlewarePhase = 'afterReducer'
const actualMiddlewarePhases = ['beforeReducer', 'afterReducer'] as const
const defaultErrorHandler: ListenerErrorHandler = (...args: unknown[]) => {
console.error('action-listener-middleware-error', ...args)
}

/**
* @alpha
Expand All @@ -239,7 +278,10 @@ export function createActionListenerMiddleware<
}

const listenerMap = new Map<string, ListenerEntry>()
const { extra } = middlewareOptions
const { extra, onError = defaultErrorHandler } =
middlewareOptions

assertFunction(onError, 'onError')

const middleware: Middleware<
{
Expand Down Expand Up @@ -277,8 +319,17 @@ export function createActionListenerMiddleware<
for (let entry of listenerMap.values()) {
const runThisPhase =
entry.when === 'both' || entry.when === currentPhase
const runListener =
runThisPhase && entry.predicate(action, currentState, originalState)

let runListener = runThisPhase

if (runListener) {
try {
runListener = entry.predicate(action, currentState, originalState)
} catch (predicateError) {
safelyNotifyError(onError, predicateError)
}
}

if (!runListener) {
continue
}
Expand All @@ -293,8 +344,8 @@ export function createActionListenerMiddleware<
extra,
unsubscribe: entry.unsubscribe,
})
} catch (err) {
// ignore errors deliberately
} catch (listenerError) {
safelyNotifyError(onListenerError, listenerError)
}
}
if (currentPhase === 'beforeReducer') {
Expand Down

0 comments on commit e2b9b1c

Please sign in to comment.