Skip to content

Commit 6a898b0

Browse files
committed
Treat 503 as an expected authentication response
This avoids spamming error reports on a 503 and instead uses the auth failure delay mechanism which will reduce the load we create on the API and also on openvpn from reconnect attempts and help reduce subsequent 503s and other slowness Change-type: patch
1 parent 1f18bba commit 6a898b0

1 file changed

Lines changed: 39 additions & 16 deletions

File tree

src/api.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,46 @@ const fromLocalHost: express.RequestHandler = (req, res, next) => {
4747
next();
4848
};
4949

50-
const checkDeviceAuth = memoize(
51-
async (username: string, password: string) => {
52-
const { statusCode } = await pooledRequest.get({
53-
url: `${BALENA_API_INTERNAL_HOST}/services/vpn/auth/${username}`,
54-
...getPassthrough(`Bearer ${password}`),
55-
});
56-
if ([200, 401, 403].includes(statusCode)) {
57-
return statusCode;
50+
const checkDeviceAuth = (() => {
51+
class ExpectedAuthError extends Error {
52+
constructor(public statusCode: number) {
53+
super();
5854
}
59-
throw new Error(`Unexpected status code from the API: ${statusCode}`);
60-
},
61-
{
62-
maxAge: VPN_AUTH_CACHE_TIMEOUT,
63-
primitive: true,
64-
promise: true,
65-
},
66-
);
55+
}
56+
const $checkDeviceAuth = memoize(
57+
async (username: string, password: string) => {
58+
const { statusCode } = await pooledRequest.get({
59+
url: `${BALENA_API_INTERNAL_HOST}/services/vpn/auth/${username}`,
60+
...getPassthrough(`Bearer ${password}`),
61+
});
62+
if ([200, 401, 403].includes(statusCode)) {
63+
return statusCode;
64+
}
65+
if (statusCode === 503) {
66+
// 503 is an expected error code but we don't want to cache it, so we throw a special error that will not be cached
67+
// but will be caught and and have the actual status code returned to the client so it can do normal failure handling
68+
// (eg delaying to reduce load).
69+
throw new ExpectedAuthError(statusCode);
70+
}
71+
throw new Error(`Unexpected status code from the API: ${statusCode}`);
72+
},
73+
{
74+
maxAge: VPN_AUTH_CACHE_TIMEOUT,
75+
primitive: true,
76+
promise: true,
77+
},
78+
);
79+
return async (username: string, password: string) => {
80+
try {
81+
return await $checkDeviceAuth(username, password);
82+
} catch (err) {
83+
if (err instanceof ExpectedAuthError) {
84+
return err.statusCode;
85+
}
86+
throw err;
87+
}
88+
};
89+
})();
6790

6891
export const apiFactory = (serviceId: number) => {
6992
const api = express.Router();

0 commit comments

Comments
 (0)