Skip to content

Commit d9ced41

Browse files
authored
Chore: retry deployment logs polling (#128)
1 parent 8ebde7a commit d9ced41

7 files changed

Lines changed: 108 additions & 3893 deletions

File tree

node/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ You can compile and run the CLI from source by cloning the repo from Github and
154154
```bash
155155
# Clone the repo from github
156156
# Make sure env0 lib is not installed globally
157-
yarn install
158-
yarn link # link your local copy of the CLI to your terminal path
157+
npm install
158+
npm link # link your local copy of the CLI to your terminal path
159159
```
160160

161161
### Development flow:

node/npm-shrinkwrap.json

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"fs-extra": "9.0.1",
3939
"inquirer": "7.3.3",
4040
"lodash": "4.17.21",
41+
"p-retry": "4.6.2",
4142
"update-notifier": "6.0.2",
4243
"winston": "3.3.4"
4344
},

node/src/lib/deploy-utils.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const Env0ApiClient = require('./api-client');
22
const logger = require('./logger');
33
const { options } = require('../config/constants');
4-
const { convertStringToBoolean, removeEmptyValuesFromObj } = require('./general-utils');
4+
const { convertStringToBoolean, removeEmptyValuesFromObj, withRetry } = require('./general-utils');
55
const { isEmpty } = require('lodash');
66

77
const {
@@ -33,6 +33,18 @@ class DeployUtils {
3333
return await apiClient.callApi('get', `environments/deployments/${deploymentLogId}`);
3434
}
3535

36+
async getDeploymentSteps(deploymentLogId) {
37+
return await apiClient.callApi('get', `deployments/${deploymentLogId}/steps`)
38+
}
39+
40+
async getDeploymentStepLog(deploymentLogId, stepName, startTime) {
41+
return await apiClient.callApi(
42+
'get',
43+
`deployments/${deploymentLogId}/steps/${stepName}/log`,
44+
{ params: { startTime } }
45+
)
46+
}
47+
3648
async updateEnvironment(environment, data) {
3749
await apiClient.callApi('put', `environments/${environment.id}`, { data });
3850
}
@@ -90,14 +102,12 @@ class DeployUtils {
90102
let startTime = undefined;
91103

92104
do {
93-
const steps = await apiClient.callApi('get', `deployments/${deploymentLogId}/steps`);
105+
const steps = await withRetry(() => this.getDeploymentSteps(deploymentLogId));
94106
const { status } = steps.find(step => step.name === stepName);
95107
const stepInProgress = status === 'IN_PROGRESS';
96108

97-
const { events, nextStartTime, hasMoreLogs } = await apiClient.callApi(
98-
'get',
99-
`deployments/${deploymentLogId}/steps/${stepName}/log`,
100-
{ params: { startTime } }
109+
const { events, nextStartTime, hasMoreLogs } = await withRetry(
110+
() => this.getDeploymentStepLog(deploymentLogId, stepName, startTime)
101111
);
102112

103113
events.forEach(event => logger.info(event.message));
@@ -112,7 +122,7 @@ class DeployUtils {
112122
async processDeploymentSteps(deploymentLogId, stepsToSkip) {
113123
const doneSteps = [];
114124

115-
const steps = await apiClient.callApi('get', `deployments/${deploymentLogId}/steps`);
125+
const steps = await this.getDeploymentSteps(deploymentLogId);
116126

117127
for (const step of steps) {
118128
const alreadyLogged = stepsToSkip.includes(step.name);
@@ -144,7 +154,7 @@ class DeployUtils {
144154
}
145155

146156
while (true) {
147-
const { type, status } = await this.getDeployment(deployment.id);
157+
const { type, status } = await withRetry(() => this.getDeployment(deployment.id));
148158

149159
if (status === 'QUEUED') logger.info('Queued deployment is still waiting for earlier deployments to finish...');
150160

node/src/lib/general-utils.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
const pRetry = require('p-retry');
2+
13
const convertStringToBoolean = str => {
24
if (str === 'true') return true;
35
if (str === 'false') return false;
46
};
57

68
const removeEmptyValuesFromObj = payload => JSON.parse(JSON.stringify(payload));
79

10+
const withRetry = (promiseFn) => pRetry(promiseFn, { retries: 2 });
11+
812
module.exports = {
913
convertStringToBoolean,
10-
removeEmptyValuesFromObj
14+
removeEmptyValuesFromObj,
15+
withRetry
1116
};

node/tests/lib/deploy-utils.spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,42 @@ describe('deploy utils', () => {
161161
{ params: { startTime: mockNextStartTime } }
162162
);
163163
});
164+
165+
describe('when there is a failure', () => {
166+
it('should retry when polling on deployment steps fails', async () => {
167+
mockCallApi.mockRejectedValueOnce(new Error('fail!'));
168+
mockCallApi.mockResolvedValueOnce([mockStep]);
169+
mockCallApi.mockResolvedValueOnce({
170+
events: [],
171+
hasMoreLogs: false
172+
});
173+
174+
await deployUtils.writeDeploymentStepLog(mockDeploymentId, mockStep.name);
175+
176+
expect(mockCallApi).toHaveBeenNthCalledWith(1, 'get', `deployments/${mockDeploymentId}/steps`)
177+
expect(mockCallApi).toHaveBeenNthCalledWith(2, 'get', `deployments/${mockDeploymentId}/steps`)
178+
});
179+
180+
it('should retry when polling on deployment step log fails', async () => {
181+
mockCallApi.mockResolvedValueOnce([mockStep]);
182+
mockCallApi.mockRejectedValueOnce(new Error('fail!'));
183+
mockCallApi.mockResolvedValueOnce({
184+
events: [],
185+
hasMoreLogs: false
186+
});
187+
188+
await deployUtils.writeDeploymentStepLog(mockDeploymentId, mockStep.name);
189+
190+
expect(mockCallApi).toHaveBeenNthCalledWith(2, 'get', `deployments/${mockDeploymentId}/steps/${mockStep.name}/log`, {
191+
params: { startTime: undefined }
192+
})
193+
expect(mockCallApi).toHaveBeenNthCalledWith(3, 'get', `deployments/${mockDeploymentId}/steps/${mockStep.name}/log`, {
194+
params: { startTime: undefined }
195+
})
196+
});
197+
})
198+
199+
164200
});
165201

166202
describe('create and deploy environment', () => {

0 commit comments

Comments
 (0)