# Event Handlers

Event handlers are typically used to create read model populators and process managers.  
The factory functions used to create `Event Handlers` are returned from `createDomain`.

For example:

```ts
const { createHandler } = createDomain(
  { provider }, // provider from createProvider()
  { user, profile, posts } // Aggregates from createAggregate<...>()
)
```

## How It Works

Once the `EventHandler` has been started, the **Event Handler Loop** will:

1. Retrieve the `Bookmark` position using the `Provider`
2. Retrieve events after the `Bookmark` position
3. If there are:
   - No events: Wait 500ms and retry Step 2.
   - Some events:
     1. Process each event and update the remote bookmark after each successful event handled
     2. Immediately retry Step 2

## createHandler()

Note that the `Stream` type is inferred from the `Aggregate` stream names when `createDomain` is called.

```ts
function createHandler(bookmark: string, streams: Stream[], options?: HandlerOptions): EventHandler
```

### HandlerOptions

```ts
type HandlerOptions = {
  tailStream?: boolean // Defaults to false
  alwaysTailStream?: boolean // Defaults to false
  continueOnError?: boolean // Defaults to false
}
```

#### continueOnError

When an event handler function throws, the event handler will invoke the `Provider.onError` function then continue processing events.  
By default event handlers will stop processing events until the handler no longer throws.

#### tailStream

When the event handler is started for the first time, the handler will begin at the end of the stream(s) history

#### alwaysTailStream

Every time the event handler is started, the handler will begin at the end of the stream(s) history

## EventHandler

### Handler

```ts
type Handler = (aggregateId: string, event: Event, meta: EventMeta) => Promise<void>
```

The `Event` type is narrowed using the `stream` and `eventType` parameters from calling `handle(stream, eventType, handler)`.

### handle

```ts
function handle(stream: string, eventType: string, handler: Handler)
```

The `stream` and `eventType` parameters are literals that are derived when `createDomain` is called.  
The `eventType` will only allow event types from the `stream` you passed in.

### start()

Begins the **Event Handler Loop**. Typically called when starting your service.  
The handler will

### stop()

Stops processing events. Not typically called.

### runOnce()

Typically used for integration testing.  
`runOnce()` will handle all unprocessed events regardless of the `start`/`stop` state of the handler.

### reset()

Resets the internal bookmark of the event handler.  
This forces the handler to retrieve the remote state of the bookmark on the next iteration.

## Example

```ts
import { createHandler } from '...'

const userModel = createHandler('users-model', ['users'])

userModel.handle('users', 'userCreated', async (id, event, meta) => {
  await mongo.collection('users').insertOne({
    userId: id,
    name: event.name,
    createdAt: meta.timestamp,
  })
})

userModel.start()
```
