Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to latest asyncforge #11

Merged
merged 8 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 11 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@ npm i fastify fastify-asyncforge
## Usage

```js
// App.js
// app.mjs
import fastify from 'fastify'
import { start } from 'fastify-asyncforge'
import doWork from './do-work.mjs'
import asyncforge, { logger } from 'fastify-asyncforge'

const app = fastify({
logger: true
})
await app.register(asyncforge)

// It's fundamental that `start` is called before any other plugins are registered, otherwise the helpers
// would not work as expected
await start(app)
app.runInAsyncScope(() => {
logger().info('hello')
})

app.decorate('foo', 'bar')
app.decorateRequest('a')
Expand Down Expand Up @@ -54,69 +55,24 @@ export default function doWork () {
}
```

### enterWith

If you need to alter the current asynchronous context, you can use the `enterWith` helper.

```js
import { before, describe, it } from "node:test";
import Fastify from "fastify";
import asyncforge, { app, start } from "fastify-asyncforge";
import assert from "node:assert/strict";

let fastify;

async function build(config) {
const server = await Fastify();

server.register(asyncforge)
server.decorate("config", config);
console.log("config from memo", app().config);

return server;
}

describe("support exiting from a context", () => {
before(async () => {
fastify = await build({ foo: "bar" });
});

it("throws", () => {
assert.throws(app);
});

it("does not throw using enterWith", () => {
fastify.enterWith();
assert.equal(app(), fastify);
});
});
```

## Usage together with other async_hooks tools (e.g. DataDog, OpenTelemetry, etc)
## `.enterWith()`

If you are using `fastify-asyncforge` together with another `async_hooks` based tool,
you __must__ call `start` without adding an intermediate async function.
Alternatively, you'd need to use `.enterWith()`
In case `.runInAsyncScope()` is incovenient, you can use `.enterWith()`

```js
import fastify from 'fastify'
import asyncforge from 'fastify-asyncforge'

const fastify = Fastify()

async function wrap () {
// This is necessary to make it throw
await 1
await asyncforge.start(fastify)
}

await wrap()

// Calling .enterWith() is necessary or `asyncforge.app()` will throw
fastify.enterWith()
asyncforge.app()
```

### Notice

Note that you cannot wrap `.enterWith()` inside an async function, as it will not work.
If you are interested in knowing more, read https://github.com/nodejs/node/issues/53037.

## License
Expand Down
16 changes: 7 additions & 9 deletions example/app.js → example/app.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
'use strict'

const fastify = require('fastify')
const doWork = require('./do-work')
const { logger, start } = require('../index')
import fastify from 'fastify'
import doWork from './do-work.mjs'
import asyncforge, { logger } from '../index.js'

const app = fastify({
logger: true
})
app.register(require('../index'))

start(app)
await app.register(asyncforge)

logger().info('hello')
app.runInAsyncScope(() => {
logger().info('hello')
})

app.decorate('foo', 'bar')
app.decorateRequest('a')
Expand Down
6 changes: 2 additions & 4 deletions example/do-work.js → example/do-work.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use strict'
import { logger, app, request, reply } from '../index.js'

const { logger, app, request, reply } = require('../')

module.exports = function doWork () {
export default function doWork () {
const log = logger()
log.info({
foo: app().foo,
Expand Down
3 changes: 2 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {

declare module "fastify" {
interface FastifyInstance {
enterWith: () => void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not remove the enterWith type, is still there

runInAsyncScope<T> (fn: () => T) : T;
enterWith() : void
}
}

Expand Down
54 changes: 29 additions & 25 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,51 @@
'use strict'

const fp = require('fastify-plugin')
const { memo, setAll } = require('asyncforge')
const { memo, create } = require('asyncforge')

const app = memo('fastify.app')
const request = memo('fastify.request')
const reply = memo('fastify.reply')
const logger = memo('fastify.logger')

const fastifyAsyncForge = fp(function (fastify, opts, next) {
fastify.decorate('runInAsyncScope', function (fn) {
const store = create()
return store.run(() => {
app.set(this)
logger.set(this.log)
return fn()
})
})

fastify.decorate('enterWith', function () {
try {
app()
} catch {
setAll({
[app.key]: this,
[logger.key]: this.log
})
}
const store = create()
store.enterWith()
app.set(this)
logger.set(this.log)
})

fastify.addHook('onRequest', async function (req, res) {
setAll({
[app.key]: this,
[request.key]: req,
[reply.key]: res,
[logger.key]: req.log
fastify.addHook('onRequest', function (req, res, next) {
const store = create()

// We use callbacks because we cannot propagate through async/await
store.run(() => {
app.set(this)
request.set(req)
reply.set(res)
logger.set(req.log)
next()
})
})
next()
})

function start (fastify) {
setAll({
[app.key]: fastify,
[logger.key]: fastify.log
create(() => {
app.set(fastify)
logger.set(fastify.log)
next()
})

return fastify.register(fastifyAsyncForge)
}
})

module.exports = fastifyAsyncForge
module.exports.start = start
module.exports.app = app
module.exports.request = request
module.exports.reply = reply
Expand Down
2 changes: 1 addition & 1 deletion index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ const fastifyInstance = fastify();
expectAssignable<FastifyInstance>(fastifyInstance.register(fastifyasyncforge));
expectAssignable<FastifyPluginCallback>(fastifyasyncforge);
expectType<void>(fastifyInstance.enterWith());
expectType<number>(fastifyInstance.runInAsyncScope(() => 42));

// app
expectAssignable<FastifyInstance>(fastifyInstance);
expectAssignable<FastifyInstance>(app());
expectType<void>(app().enterWith());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, we should be able access the enterWith decorator from TypeScript

expectAssignable<FastifyInstance>(app<FastifyInstance<RawServerDefault>>());
expectError<FastifyInstance>(app<string>());
expectError<FastifyInstance>({});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"tsd": "^0.31.0"
},
"dependencies": {
"asyncforge": "^0.2.0",
"asyncforge": "^0.5.0",
"fastify-plugin": "^4.5.1"
},
"types": "index.d.ts"
Expand Down
17 changes: 3 additions & 14 deletions test/async-hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,7 @@ test('async_hooks lose context', async (t) => {
const fastify = Fastify()
t.after(() => fastify.close())

async function wrap () {
// This is necessary to make it throw
await 1
await fastifyAsyncForge.start(fastify)
}

await wrap()
await fastify.register(fastifyAsyncForge)

// This is expected to throw due to https://github.com/nodejs/node/issues/53037
p.throws(logger)
Expand Down Expand Up @@ -51,13 +45,8 @@ test('enterWith fixes it', async (t) => {
const fastify = Fastify()
t.after(() => fastify.close())

async function wrap () {
await 1
await fastifyAsyncForge.start(fastify)
}

await wrap()
await fastify.enterWith()
await fastify.register(fastifyAsyncForge)
fastify.enterWith()

p.strictEqual(logger(), fastify.log)
p.strictEqual(app(), fastify)
Expand Down
Loading
Loading