Skip to content

Commit 5d84036

Browse files
Merge pull request #653 from snyk/feat/restart-informers-if-error-occurred
feat: restart k8s informers on error event (e.g idle connection)
2 parents eddd7d0 + 82a61b6 commit 5d84036

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

src/supervisor/watchers/handlers/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { makeInformer, ADD, DELETE, UPDATE, KubernetesObject } from '@kubernetes/client-node';
1+
import { makeInformer, ADD, DELETE, ERROR, UPDATE, KubernetesObject } from '@kubernetes/client-node';
22
import { logger } from '../../../common/logger';
33
import { WorkloadKind } from '../../types';
44
import { podWatchHandler, podDeletedHandler } from './pod';
@@ -12,6 +12,7 @@ import { statefulSetWatchHandler } from './stateful-set';
1212
import { k8sApi, kubeConfig } from '../../cluster';
1313
import * as kubernetesApiWrappers from '../../kuberenetes-api-wrappers';
1414
import { IWorkloadWatchMetadata, FALSY_WORKLOAD_NAME_MARKER } from './types';
15+
import { ECONNRESET_ERROR_CODE } from '../types';
1516

1617
/**
1718
* This map is used in combination with the kubernetes-client Informer API
@@ -109,6 +110,20 @@ export function setupInformer(namespace: string, workloadKind: WorkloadKind) {
109110

110111
const informer = makeInformer<KubernetesObject>(kubeConfig, namespacedEndpoint, loggedListMethod);
111112

113+
informer.on(ERROR, (err) => {
114+
// Types from client library insists that callback is of type KubernetesObject
115+
if ((err as any).code === ECONNRESET_ERROR_CODE) {
116+
logger.debug(`informer ${ECONNRESET_ERROR_CODE} occurred, restarting informer`);
117+
118+
// Restart informer after 1sec
119+
setTimeout(() => {
120+
informer.start();
121+
}, 1000);
122+
} else {
123+
logger.error({ err }, 'unexpected informer error event occurred');
124+
}
125+
});
126+
112127
for (const informerVerb of Object.keys(workloadMetadata.handlers)) {
113128
informer.on(informerVerb, async (watchedWorkload) => {
114129
try {

src/supervisor/watchers/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { makeInformer, ADD } from '@kubernetes/client-node';
1+
import { makeInformer, ADD, ERROR } from '@kubernetes/client-node';
22
import { V1Namespace } from '@kubernetes/client-node';
33

44
import { logger } from '../../common/logger';
55
import { config } from '../../common/config';
66
import { WorkloadKind } from '../types';
7+
import { ECONNRESET_ERROR_CODE } from './types';
78
import { setupInformer } from './handlers';
89
import { kubeConfig, k8sApi } from '../cluster';
910
import * as kubernetesApiWrappers from '../kuberenetes-api-wrappers';
@@ -67,6 +68,20 @@ function setupWatchesForCluster(): void {
6768
},
6869
);
6970

71+
informer.on(ERROR, (err) => {
72+
// Types from client library insists that callback is of type V1Namespace
73+
if ((err as any).code === ECONNRESET_ERROR_CODE) {
74+
logger.debug(`namespace informer ${ECONNRESET_ERROR_CODE} occurred, restarting informer`);
75+
76+
// Restart informer after 1sec
77+
setTimeout(() => {
78+
informer.start();
79+
}, 1000);
80+
} else {
81+
logger.error({ err }, 'unexpected namespace informer error event occurred');
82+
}
83+
});
84+
7085
informer.on(ADD, (namespace: V1Namespace) => {
7186
try {
7287
const namespaceName = extractNamespaceName(namespace);

src/supervisor/watchers/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ export enum PodPhase {
1010
// For some reason the state of the pod could not be obtained.
1111
Unknown = 'Unknown',
1212
}
13+
14+
export const ECONNRESET_ERROR_CODE = 'ECONNRESET';

0 commit comments

Comments
 (0)