Skip to content

Commit

Permalink
feat: Add configurable timeouts (#320)
Browse files Browse the repository at this point in the history
* Timeouts for non-batch mode

* Modifications to logging

* Fixing an unrelated [object object] message in breadcrumbs.

* Wired-in DEFAULT_TIMOUT for 5000ms (this seems to be the *internal* default of Node's http/https libs as well)

* Adding dedicated batchTimeout

* Clarifying timeout behaviour

* Prettier

* Addressing PR comments

* Documentation

* Prettier
  • Loading branch information
TheRealAgentK authored Oct 3, 2024
1 parent c326693 commit f656198
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 9 deletions.
32 changes: 27 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,25 @@ The `send()` function is asynchronous and returns a `Promise` of type `IncomingM

Note that `IncomingMessage` can be `null` if the request was stored because the application was offline.

`IncomingMessage` is the response from the Raygun API - there's nothing in the body, it's just a status code response.
If everything went ok, you'll get a 202 response code.
Otherwise, we throw 401 for incorrect API keys, 403 if you're over your plan limits, or anything in the 500+ range for internal errors.
`IncomingMessage` is the response from the Raygun API - there's nothing in the body, it's just a status code response. If everything went ok, you'll get a 202 response code.
Otherwise, we return 401 for incorrect API keys, 403 if you're over your plan limits, or anything in the 500+ range for internal errors.

We use the nodejs http/https library to make the POST to Raygun, you can see more documentation about that callback here: https://nodejs.org/api/http.html#http_http_request_options_callback
We use the nodejs http/https library to make the POST to Raygun, you can see more documentation about that callback here: https://nodejs.org/api/http.html#http_http_request_options_callback .

You can `await` the call to obtain the result, or use `then/catch`.

The default timeout for the transport layer is 5000ms. You can override this value by setting a custom `timeout` (also in ms) when you initialize the Raygun client:

```typescript
import * as Raygun from 'raygun';

const raygunClient = new Raygun.Client().init({
apiKey: 'YOUR_API_KEY',
...
timeout: 3000 // defaults to 5000ms
});
```

#### Using `await`

Use `await` to obtain the `IncomingMessage`, remember to `catch` any possible thrown errors from the `send()` method.
Expand Down Expand Up @@ -418,7 +429,18 @@ If your application generates and reports large volumes of errors, especially in

You can control how often batches are processed and sent by providing a `batchFrequency` option, which is a number in milliseconds.

In a future version the batch transport will likely be enabled by default.
The default timeout for batch transport calls is 5000ms. You can override this value by setting a custom `timeout` (also in ms) when you initialize the Raygun client:

```typescript
import * as Raygun from 'raygun';

const raygunClient = new Raygun.Client().init({
apiKey: 'YOUR_API_KEY',
batch: true,
batchFrequency: 5000, // defaults to 1000ms (every second)
timeout: 10000 // defaults to 5000ms
});
```

### Offline caching

Expand Down
2 changes: 1 addition & 1 deletion lib/raygun.breadcrumbs.express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function addRequestBreadcrumb(request: Request) {
};

debug(
`[raygun.breadcrumbs.express.ts] recorded request breadcrumb: ${internalCrumb}`,
`[raygun.breadcrumbs.express.ts] recorded request breadcrumb: ${JSON.stringify(internalCrumb, undefined, 2)}`,
);

crumbs.push(internalCrumb);
Expand Down
21 changes: 19 additions & 2 deletions lib/raygun.transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const API_HOST = "api.raygun.io";
const DEFAULT_ENDPOINT = "/entries";
const BATCH_ENDPOINT = "/entries/bulk";

const debug = require("debug")("raygun");

export function sendBatch(options: SendOptions): Promise<IncomingMessage> {
return send(options, BATCH_ENDPOINT);
}
Expand Down Expand Up @@ -57,12 +59,27 @@ export function send(
(response: IncomingMessage) => {
// request completed successfully
resolve(response);
// destroy the request after successful completion
request.destroy();
debug(
`[raygun.transport.ts] Request destroyed for message: ${options.message}`,
);
},
);

if (options.http.timeout) {
debug(`[raygun.transport.ts] Timeout set: ${options.http.timeout}ms`);
request.setTimeout(options.http.timeout, () => {
console.error(
`[Raygun4Node] request timed out while attempting to send error with message: ${options.message}`,
);
request.destroy(new Error("Request timed out"));
});
}

request.on("error", function (e) {
console.error(
`[Raygun4Node] error ${e.message} occurred while attempting to send error with message: ${options.message}`,
`[Raygun4Node] Error with details "${e.message}" occurred while attempting to send error with message: ${options.message}`,
);

// request failed
Expand All @@ -74,7 +91,7 @@ export function send(
});
} catch (e) {
console.error(
`[Raygun4Node] error ${e} occurred while attempting to send error with message: ${options.message}`,
`[Raygun4Node] Error "${e}" occurred while attempting to send error with message: ${options.message}`,
);
return Promise.reject(e);
}
Expand Down
9 changes: 8 additions & 1 deletion lib/raygun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ try {
type SendCB = (error: Error | null, items: string[] | undefined) => void;

const DEFAULT_BATCH_FREQUENCY = 1000; // ms
const DEFAULT_TIMEOUT = 5000; // ms

function emptyCallback() {}

Expand All @@ -79,6 +80,8 @@ class Raygun {

_useSSL: boolean | undefined;

_timeout: number | undefined;

_onBeforeSend: Hook<Message | null> | undefined;

_offlineStorage: IOfflineStorage | undefined;
Expand Down Expand Up @@ -118,6 +121,7 @@ class Raygun {
this._port = options.port;
this._useSSL = options.useSSL !== false;
this._onBeforeSend = options.onBeforeSend;
this._timeout = options.timeout;
this._isOffline = options.isOffline;
this._groupingKey = options.groupingKey;
this._tags = options.tags;
Expand All @@ -144,6 +148,7 @@ class Raygun {
port: this._port,
useSSL: !!this._useSSL,
apiKey: this._apiKey,
timeout: this._timeout || DEFAULT_TIMEOUT,
},
});
}
Expand Down Expand Up @@ -570,7 +575,8 @@ class Raygun {
host: this._host,
port: this._port,
useSSL: !!this._useSSL,
apiKey,
apiKey: apiKey,
timeout: this._timeout || DEFAULT_TIMEOUT,
},
},
};
Expand All @@ -583,6 +589,7 @@ class Raygun {
port: this._port,
useSSL: this._useSSL || false,
apiKey: this._apiKey || "",
timeout: this._timeout || DEFAULT_TIMEOUT,
};

return {
Expand Down
2 changes: 2 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export type HTTPOptions = {
host: string | undefined;
port: number | undefined;
apiKey: string;
timeout?: number;
};

// Allow any because users are free to set anything as CustomData
Expand Down Expand Up @@ -179,6 +180,7 @@ export type RaygunOptions = {
host?: string;
port?: number;
useSSL?: boolean;
timeout?: number;
onBeforeSend?: Hook<Message>;
offlineStorage?: IOfflineStorage;
offlineStorageOptions?: OfflineStorageOptions;
Expand Down
18 changes: 18 additions & 0 deletions test/raygun_async_send_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ test("async send complex", {}, function (t) {
});
});

test("async send complex with timeout", {}, function (t) {
t.plan(1);

let client = new Raygun.Client()
.init({ apiKey: API_KEY, timeout: 5000 })
.setVersion("1.0.0.0");

client
.send(new Error())
.then((response) => {
t.equal(response.statusCode, 202);
t.end();
})
.catch((err) => {
t.fail(err);
});
});

test("async send with inner error", {}, function (t) {
t.plan(1);

Expand Down

0 comments on commit f656198

Please sign in to comment.