@dev-blinq/cucumber_client 1.0.1186-dev → 1.0.1188-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -383,7 +383,7 @@ class LocalAgent {
383
383
  error: command.data.errorMessage,
384
384
  });
385
385
  agent.stepFailResolve(command.data.errorMessage);
386
- logger.info("Step fail, " + command.data.errorMessage);
386
+ logger.error("Step fail, " + command.data.errorMessage);
387
387
  } else {
388
388
  agent.stepEndResolve();
389
389
  logger.info("Step end");
@@ -193,7 +193,8 @@ class ScenarioReport {
193
193
  fs.writeFileSync(path, zipBlob);
194
194
  return path;
195
195
  }
196
-
196
+ // Note to future self:
197
+ // Increased the max retries to 3 and added exponential backoff to increase consistency but traded off availability :)
197
198
  async _uploadScenario() {
198
199
  try {
199
200
  const scenarioDoc = await this.scenarioUploadService.createScenarioDocument(this.name);
@@ -201,62 +202,91 @@ class ScenarioReport {
201
202
  const projectId = scenarioDoc.project_id;
202
203
  this.scenario_id = scenarioDocId;
203
204
  this._saveToFile();
204
-
205
- // console.log("scenarioDocId", scenarioDocId);
206
205
  await this.sendRetrainStats(scenarioDocId);
207
- // create zip file
208
206
  if (process.env.NODE_ENV_BLINQ === "local") {
209
- const zipFilePath = await this.createScenarioZip();
210
- // upload to server
211
- const formData = new FormData();
212
- // const file = File(zipFileBlob, "report.zip");
213
- formData.append(scenarioDocId, fs.readFileSync(zipFilePath), "report.zip");
214
- await this.scenarioUploadService.upload(formData);
207
+ await this._uploadLocalBundle(scenarioDocId);
215
208
  } else {
216
- const report = getJsonReport(this);
217
- fs.writeFileSync(path.join(this.scenarioPath, "scenario.json"), JSON.stringify(report, null, 2));
218
- const fileUris = [
219
- ...this.getFileUrisScreenShotDir(this.scenarioPath),
220
- "scenario.json",
221
- "network.json",
222
- "editorLogs.log",
223
- ];
224
- const networkJsonPath = path.join(this.scenarioPath, "network.json");
225
- if (!fs.existsSync(networkJsonPath)) {
226
- fs.writeFileSync(networkJsonPath, JSON.stringify({}), "utf-8");
227
- }
228
- const presignedUrls = await this.scenarioUploadService.getPresignedUrls(fileUris, scenarioDocId);
229
- for (let i = 0; i < fileUris.length; i += BATCH_SIZE) {
230
- const batch = fileUris.slice(i, Math.min(i + BATCH_SIZE, fileUris.length));
231
- await Promise.all(
232
- batch
233
- .filter((fileUrl) => presignedUrls[fileUrl] !== undefined)
234
- .map(async (fileUrl) => {
235
- const filePath = path.join(this.scenarioPath, fileUrl);
236
- for (let j = 0; j < MAX_RETRIES; j++) {
237
- const success = await this.scenarioUploadService.uploadFile(filePath, presignedUrls[fileUrl]);
238
- if (success) {
239
- return;
240
- }
241
- }
242
- console.error("Failed to upload file", fileUrl);
243
- })
244
- );
245
- }
246
- await this.scenarioUploadService.uploadComplete(scenarioDocId, projectId);
209
+ await this._uploadRemoteBundle(scenarioDocId, projectId);
247
210
  }
248
211
  logger.info("Scenario uploaded successfully");
249
-
250
212
  this.logReportLink(projectId, scenarioDocId);
251
-
252
- // delete zip file
253
- // fs.unlinkSync(this.scenarioPath + '/example.zip');
254
213
  } catch (err) {
255
- logger.info("Failed to upload scenario - ignored");
256
- logger.debug(err);
257
- //console.error(err);
214
+ logger.error("Scenario uploaded failed");
215
+ logger.debug("Error while uploading : ", err);
258
216
  }
259
217
  }
218
+ // Local environment uploader decomposed the function for better readability
219
+ async _uploadLocalBundle(scenarioDocId) {
220
+ const zipFilePath = await this.createScenarioZip();
221
+ const formData = new FormData();
222
+ formData.append("scenarioId", scenarioDocId);
223
+ formData.append("file", fs.createReadStream(zipFilePath));
224
+
225
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
226
+ try {
227
+ await this.scenarioUploadService.upload(formData);
228
+ fs.unlinkSync(zipFilePath);
229
+ return;
230
+ } catch (err) {
231
+ logger.debug("Local upload attempt failed", { attempt, error: err });
232
+ // added delays between retries for better consistency over availability
233
+ await this._delay(2 ** attempt * 1000);
234
+ }
235
+ }
236
+ throw new Error(`Local upload failed after ${MAX_RETRIES} attempts`);
237
+ }
238
+
239
+ // decomposed the function for better readability this function is used to upload
240
+ async _uploadRemoteBundle(scenarioDocId, projectId) {
241
+ const report = getJsonReport(this);
242
+ fs.writeFileSync(path.join(this.scenarioPath, "scenario.json"), JSON.stringify(report, null, 2));
243
+
244
+ const fileUris = [
245
+ ...this.getFileUrisScreenShotDir(this.scenarioPath),
246
+ "scenario.json",
247
+ "network.json",
248
+ "editorLogs.log",
249
+ ];
250
+ const networkJsonPath = path.join(this.scenarioPath, "network.json");
251
+ if (!fs.existsSync(networkJsonPath)) {
252
+ fs.writeFileSync(networkJsonPath, JSON.stringify({}), "utf-8");
253
+ }
254
+
255
+ const presignedUrls = await this.scenarioUploadService.getPresignedUrls(fileUris, scenarioDocId);
256
+ const missing = fileUris.filter((uri) => !presignedUrls[uri]);
257
+ if (missing.length) {
258
+ throw new Error(`Missing presigned URLs for: ${missing.join(", ")}`);
259
+ }
260
+
261
+ // Upload files in batches with retries
262
+ for (let i = 0; i < fileUris.length; i += BATCH_SIZE) {
263
+ const batch = fileUris.slice(i, i + BATCH_SIZE);
264
+ await Promise.all(batch.map((uri) => this._retryUploadFile(uri, presignedUrls[uri])));
265
+ }
266
+
267
+ await this.scenarioUploadService.uploadComplete(scenarioDocId, projectId);
268
+ }
269
+
270
+ // Retry helper it will retry the upload of a file if it fails given file uri and url here Max_retires is and each retiry wait time : 2secs ,4secs, 8 secs
271
+ // Note to self : if the still upload fails a lot we have to investigate the file formats too
272
+ async _retryUploadFile(fileUri, url) {
273
+ const filePath = path.join(this.scenarioPath, fileUri);
274
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
275
+ try {
276
+ await this.scenarioUploadService.uploadFile(filePath, url);
277
+ return;
278
+ } catch (err) {
279
+ logger.debug("Upload file attempt failed ", { fileUri, attempt, error: err });
280
+ await this._delay(2 ** attempt * 1000);
281
+ }
282
+ }
283
+ throw new Error(`Failed to upload file ${fileUri} after ${MAX_RETRIES} attempts`);
284
+ }
285
+
286
+ // Utility delay can be used to delay anything (Note to self : Replace it with the built in delay function later)
287
+ _delay(ms) {
288
+ return new Promise((resolve) => setTimeout(resolve, ms));
289
+ }
260
290
 
261
291
  logReportLink(projectId, scenarioId) {
262
292
  let baseUrl = "https://www.app.blinq.io";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-blinq/cucumber_client",
3
- "version": "1.0.1186-dev",
3
+ "version": "1.0.1188-dev",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "@cucumber/tag-expressions": "^6.1.1",
29
29
  "@dev-blinq/cucumber-js": "1.0.172-dev",
30
30
  "@faker-js/faker": "^8.1.0",
31
- "automation_model": "1.0.718-dev",
31
+ "automation_model": "1.0.719-dev",
32
32
  "axios": "^1.7.4",
33
33
  "chokidar": "^3.6.0",
34
34
  "create-require": "^1.1.1",