Skip to content
Open
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
6 changes: 6 additions & 0 deletions .changeset/linear-node-entry-lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@croco/preset-node": patch
"@croco/problems-core": patch
---

Make Node entry startup and shutdown linearizable so concurrent lifecycle calls cannot leak server listeners.
62 changes: 61 additions & 1 deletion docs/problem-code-registry.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "croco.problem-code-registry.v1",
"problemCount": 583,
"problemCount": 585,
"problems": [
{
"code": "ACCESS_DENIED",
Expand Down Expand Up @@ -11132,6 +11132,66 @@
}
]
},
{
"code": "preset-node/lifecycle-conflict",
"category": "Conflict",
"status": 409,
"title": "Conflict",
"cookbookPath": "/reference/problem-recovery-cookbook/#preset-node-lifecycle-conflict",
"recovery": {
"cause": "start() was called on a Node entry that is closing or already closed.",
"userAction": "Wait for closure to finish, then create a new entry to start another server.",
"operatorAction": "Inspect Node entry ownership and the ordering of start() and close() calls.",
"retryability": "not-retryable",
"redactionPolicy": "safe-message",
"telemetry": {
"eventName": "croco.problem.warning",
"severity": "warning",
"attributes": ["problem.code", "problem.category", "problem.status"]
}
},
"lifecycle": {
"status": "active"
},
"sources": [
{
"file": "packages/preset-node/src/problems.ts",
"line": 6,
"column": 5,
"kind": "problem-constructor"
}
]
},
{
"code": "preset-node/lifecycle-io-failed",
"category": "InternalServerError",
"status": 500,
"title": "Internal Server Error",
"cookbookPath": "/reference/problem-recovery-cookbook/#preset-node-lifecycle-io-failed",
"recovery": {
"cause": "The Node server failed while starting or closing an entry.",
"userAction": "Retry only after the server or socket failure has been investigated.",
"operatorAction": "Inspect the preserved cause and the reported lifecycle operation.",
"retryability": "conditional",
"redactionPolicy": "operator-only",
"telemetry": {
"eventName": "croco.problem.error",
"severity": "error",
"attributes": ["problem.code", "problem.category", "problem.status"]
}
},
"lifecycle": {
"status": "active"
},
"sources": [
{
"file": "packages/preset-node/src/problems.ts",
"line": 20,
"column": 5,
"kind": "problem-constructor"
}
]
},
Comment thread
kang-heewon marked this conversation as resolved.
{
"code": "problems-core/invalid-extensions",
"category": "BadRequest",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
---
editUrl: false
next: false
prev: false
title: "NodeEntryLifecycleIoProblem"
---

Reports a Node server failure while starting or closing an entry.

## Extends

- [`Problem`](/api/problems-core/src/classes/problem/)

## Constructors

### Constructor

> **new NodeEntryLifecycleIoProblem**(`operation`, `cause`): `NodeEntryLifecycleIoProblem`

#### Parameters

##### operation

`"start"` \| `"close"`

##### cause

`Error`

#### Returns

`NodeEntryLifecycleIoProblem`

#### Overrides

`Problem.constructor`

## Properties

### category

> `readonly` **category**: [`ProblemCategory`](/api/problems-core/src/enumerations/problemcategory/)

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`category`](/api/problems-core/src/classes/problem/#category)

***

### cause?

> `readonly` `optional` **cause?**: `Error`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`cause`](/api/problems-core/src/classes/problem/#cause)

***

### code

> `readonly` **code**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`code`](/api/problems-core/src/classes/problem/#code)

***

### detail?

> `readonly` `optional` **detail?**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`detail`](/api/problems-core/src/classes/problem/#detail)

***

### extensions?

> `readonly` `optional` **extensions?**: [`ProblemExtensions`](/api/problems-core/src/type-aliases/problemextensions/)

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`extensions`](/api/problems-core/src/classes/problem/#extensions)

***

### instance?

> `readonly` `optional` **instance?**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`instance`](/api/problems-core/src/classes/problem/#instance)

***

### message

> **message**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`message`](/api/problems-core/src/classes/problem/#message)

***

### name

> **name**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`name`](/api/problems-core/src/classes/problem/#name)

***

### stack?

> `optional` **stack?**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`stack`](/api/problems-core/src/classes/problem/#stack)

***

### type

> `readonly` **type**: `string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`type`](/api/problems-core/src/classes/problem/#type)

***

### stackTraceLimit

> `static` **stackTraceLimit**: `number`

The `Error.stackTraceLimit` property specifies the number of stack frames
collected by a stack trace (whether generated by `new Error().stack` or
`Error.captureStackTrace(obj)`).

The default value is `10` but may be set to any valid JavaScript number. Changes
will affect any stack trace captured _after_ the value has been changed.

If set to a non-number value, or set to a negative number, stack traces will
not capture any frames.

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`stackTraceLimit`](/api/problems-core/src/classes/problem/#stacktracelimit)

## Accessors

### status

#### Get Signature

> **get** **status**(): `number`

##### Returns

`number`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`status`](/api/problems-core/src/classes/problem/#status)

***

### title

#### Get Signature

> **get** **title**(): `string`

##### Returns

`string`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`title`](/api/problems-core/src/classes/problem/#title)

## Methods

### toJSON()

> **toJSON**(): [`ProblemDetails`](/api/problems-core/src/type-aliases/problemdetails/)

#### Returns

[`ProblemDetails`](/api/problems-core/src/type-aliases/problemdetails/)

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`toJSON`](/api/problems-core/src/classes/problem/#tojson)

***

### captureStackTrace()

> `static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void`

Creates a `.stack` property on `targetObject`, which when accessed returns
a string representing the location in the code at which
`Error.captureStackTrace()` was called.

```js
const myObject = {};
Error.captureStackTrace(myObject);
myObject.stack; // Similar to `new Error().stack`
```

The first line of the trace will be prefixed with
`${myObject.name}: ${myObject.message}`.

The optional `constructorOpt` argument accepts a function. If given, all frames
above `constructorOpt`, including `constructorOpt`, will be omitted from the
generated stack trace.

The `constructorOpt` argument is useful for hiding implementation
details of error generation from the user. For instance:

```js
function a() {
b();
}

function b() {
c();
}

function c() {
// Create an error without stack trace to avoid calculating the stack trace twice.
const { stackTraceLimit } = Error;
Error.stackTraceLimit = 0;
const error = new Error();
Error.stackTraceLimit = stackTraceLimit;

// Capture the stack trace above function b
Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
throw error;
}

a();
```

#### Parameters

##### targetObject

`object`

##### constructorOpt?

`Function`

#### Returns

`void`

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`captureStackTrace`](/api/problems-core/src/classes/problem/#capturestacktrace)

***

### prepareStackTrace()

> `static` **prepareStackTrace**(`err`, `stackTraces`): `any`

#### Parameters

##### err

`Error`

##### stackTraces

`CallSite`[]

#### Returns

`any`

#### See

https://v8.dev/docs/stack-trace-api#customizing-stack-traces

#### Inherited from

[`Problem`](/api/problems-core/src/classes/problem/).[`prepareStackTrace`](/api/problems-core/src/classes/problem/#preparestacktrace)
Loading
Loading