@forzalabs/remora 1.2.9 → 1.2.11
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.
- package/CHANGELOG.md +7 -0
- package/index.js +517 -301
- package/json_schemas/consumer-schema.json +4 -0
- package/package.json +1 -1
- package/workers/ExecutorWorker.js +513 -294
package/index.js
CHANGED
|
@@ -10293,7 +10293,7 @@ var require_node2 = __commonJS({
|
|
|
10293
10293
|
var require_tail_file = __commonJS({
|
|
10294
10294
|
"../../packages/logger/node_modules/winston/lib/winston/tail-file.js"(exports2, module2) {
|
|
10295
10295
|
"use strict";
|
|
10296
|
-
var
|
|
10296
|
+
var fs24 = require("fs");
|
|
10297
10297
|
var { StringDecoder } = require("string_decoder");
|
|
10298
10298
|
var { Stream } = require_readable();
|
|
10299
10299
|
function noop() {
|
|
@@ -10314,7 +10314,7 @@ var require_tail_file = __commonJS({
|
|
|
10314
10314
|
stream.emit("end");
|
|
10315
10315
|
stream.emit("close");
|
|
10316
10316
|
};
|
|
10317
|
-
|
|
10317
|
+
fs24.open(options.file, "a+", "0644", (err2, fd) => {
|
|
10318
10318
|
if (err2) {
|
|
10319
10319
|
if (!iter) {
|
|
10320
10320
|
stream.emit("error", err2);
|
|
@@ -10326,10 +10326,10 @@ var require_tail_file = __commonJS({
|
|
|
10326
10326
|
}
|
|
10327
10327
|
(function read() {
|
|
10328
10328
|
if (stream.destroyed) {
|
|
10329
|
-
|
|
10329
|
+
fs24.close(fd, noop);
|
|
10330
10330
|
return;
|
|
10331
10331
|
}
|
|
10332
|
-
return
|
|
10332
|
+
return fs24.read(fd, buffer, 0, buffer.length, pos, (error, bytes) => {
|
|
10333
10333
|
if (error) {
|
|
10334
10334
|
if (!iter) {
|
|
10335
10335
|
stream.emit("error", error);
|
|
@@ -10388,7 +10388,7 @@ var require_tail_file = __commonJS({
|
|
|
10388
10388
|
var require_file = __commonJS({
|
|
10389
10389
|
"../../packages/logger/node_modules/winston/lib/winston/transports/file.js"(exports2, module2) {
|
|
10390
10390
|
"use strict";
|
|
10391
|
-
var
|
|
10391
|
+
var fs24 = require("fs");
|
|
10392
10392
|
var path24 = require("path");
|
|
10393
10393
|
var asyncSeries = require_series();
|
|
10394
10394
|
var zlib2 = require("zlib");
|
|
@@ -10593,7 +10593,7 @@ var require_file = __commonJS({
|
|
|
10593
10593
|
let buff = "";
|
|
10594
10594
|
let results = [];
|
|
10595
10595
|
let row = 0;
|
|
10596
|
-
const stream =
|
|
10596
|
+
const stream = fs24.createReadStream(file, {
|
|
10597
10597
|
encoding: "utf8"
|
|
10598
10598
|
});
|
|
10599
10599
|
stream.on("error", (err2) => {
|
|
@@ -10745,7 +10745,7 @@ var require_file = __commonJS({
|
|
|
10745
10745
|
stat(callback) {
|
|
10746
10746
|
const target = this._getFile();
|
|
10747
10747
|
const fullpath = path24.join(this.dirname, target);
|
|
10748
|
-
|
|
10748
|
+
fs24.stat(fullpath, (err2, stat) => {
|
|
10749
10749
|
if (err2 && err2.code === "ENOENT") {
|
|
10750
10750
|
debug("ENOENT\xA0ok", fullpath);
|
|
10751
10751
|
this.filename = target;
|
|
@@ -10850,7 +10850,7 @@ var require_file = __commonJS({
|
|
|
10850
10850
|
_createStream(source) {
|
|
10851
10851
|
const fullpath = path24.join(this.dirname, this.filename);
|
|
10852
10852
|
debug("create stream start", fullpath, this.options);
|
|
10853
|
-
const dest =
|
|
10853
|
+
const dest = fs24.createWriteStream(fullpath, this.options).on("error", (err2) => debug(err2)).on("close", () => debug("close", dest.path, dest.bytesWritten)).on("open", () => {
|
|
10854
10854
|
debug("file open ok", fullpath);
|
|
10855
10855
|
this.emit("open", fullpath);
|
|
10856
10856
|
source.pipe(dest);
|
|
@@ -10929,7 +10929,7 @@ var require_file = __commonJS({
|
|
|
10929
10929
|
const isZipped = this.zippedArchive ? ".gz" : "";
|
|
10930
10930
|
const filePath = `${basename}${isOldest}${ext}${isZipped}`;
|
|
10931
10931
|
const target = path24.join(this.dirname, filePath);
|
|
10932
|
-
|
|
10932
|
+
fs24.unlink(target, callback);
|
|
10933
10933
|
}
|
|
10934
10934
|
/**
|
|
10935
10935
|
* Roll files forward based on integer, up to maxFiles. e.g. if base if
|
|
@@ -10952,17 +10952,17 @@ var require_file = __commonJS({
|
|
|
10952
10952
|
tasks.push(function(i, cb) {
|
|
10953
10953
|
let fileName = `${basename}${i - 1}${ext}${isZipped}`;
|
|
10954
10954
|
const tmppath = path24.join(this.dirname, fileName);
|
|
10955
|
-
|
|
10955
|
+
fs24.exists(tmppath, (exists) => {
|
|
10956
10956
|
if (!exists) {
|
|
10957
10957
|
return cb(null);
|
|
10958
10958
|
}
|
|
10959
10959
|
fileName = `${basename}${i}${ext}${isZipped}`;
|
|
10960
|
-
|
|
10960
|
+
fs24.rename(tmppath, path24.join(this.dirname, fileName), cb);
|
|
10961
10961
|
});
|
|
10962
10962
|
}.bind(this, x));
|
|
10963
10963
|
}
|
|
10964
10964
|
asyncSeries(tasks, () => {
|
|
10965
|
-
|
|
10965
|
+
fs24.rename(
|
|
10966
10966
|
path24.join(this.dirname, `${basename}${ext}${isZipped}`),
|
|
10967
10967
|
path24.join(this.dirname, `${basename}1${ext}${isZipped}`),
|
|
10968
10968
|
callback
|
|
@@ -10978,22 +10978,22 @@ var require_file = __commonJS({
|
|
|
10978
10978
|
* @private
|
|
10979
10979
|
*/
|
|
10980
10980
|
_compressFile(src, dest, callback) {
|
|
10981
|
-
|
|
10981
|
+
fs24.access(src, fs24.F_OK, (err2) => {
|
|
10982
10982
|
if (err2) {
|
|
10983
10983
|
return callback();
|
|
10984
10984
|
}
|
|
10985
10985
|
var gzip = zlib2.createGzip();
|
|
10986
|
-
var inp =
|
|
10987
|
-
var out =
|
|
10986
|
+
var inp = fs24.createReadStream(src);
|
|
10987
|
+
var out = fs24.createWriteStream(dest);
|
|
10988
10988
|
out.on("finish", () => {
|
|
10989
|
-
|
|
10989
|
+
fs24.unlink(src, callback);
|
|
10990
10990
|
});
|
|
10991
10991
|
inp.pipe(gzip).pipe(out);
|
|
10992
10992
|
});
|
|
10993
10993
|
}
|
|
10994
10994
|
_createLogDirIfNotExist(dirPath) {
|
|
10995
|
-
if (!
|
|
10996
|
-
|
|
10995
|
+
if (!fs24.existsSync(dirPath)) {
|
|
10996
|
+
fs24.mkdirSync(dirPath, { recursive: true });
|
|
10997
10997
|
}
|
|
10998
10998
|
}
|
|
10999
10999
|
};
|
|
@@ -18744,25 +18744,6 @@ var ProcessENVManagerClass = class {
|
|
|
18744
18744
|
var ProcessENVManager = new ProcessENVManagerClass();
|
|
18745
18745
|
var ProcessENVManager_default = ProcessENVManager;
|
|
18746
18746
|
|
|
18747
|
-
// ../../packages/common/src/SecretManager.ts
|
|
18748
|
-
var SecretManagerClass = class {
|
|
18749
|
-
constructor() {
|
|
18750
|
-
/**
|
|
18751
|
-
* If the value is a secret (or .env setting), replace it with the value inside the .env configuration file
|
|
18752
|
-
* Starts with "{" and ends with "}".
|
|
18753
|
-
* e.g. {AWS_ID}
|
|
18754
|
-
*/
|
|
18755
|
-
this.replaceSecret = (value) => {
|
|
18756
|
-
if (!value || value.length <= 2 || !value.startsWith("{") || !value.endsWith("}"))
|
|
18757
|
-
return value;
|
|
18758
|
-
const parsedValue = value.slice(1, value.length - 1);
|
|
18759
|
-
return ProcessENVManager_default.getEnvVariable(parsedValue);
|
|
18760
|
-
};
|
|
18761
|
-
}
|
|
18762
|
-
};
|
|
18763
|
-
var SecretManager = new SecretManagerClass();
|
|
18764
|
-
var SecretManager_default = SecretManager;
|
|
18765
|
-
|
|
18766
18747
|
// ../../packages/common/src/ExecutorScope.ts
|
|
18767
18748
|
var import_path3 = __toESM(require("path"), 1);
|
|
18768
18749
|
var import_fs3 = __toESM(require("fs"), 1);
|
|
@@ -18770,7 +18751,7 @@ var import_promises = __toESM(require("fs/promises"), 1);
|
|
|
18770
18751
|
|
|
18771
18752
|
// ../../packages/constants/src/Constants.ts
|
|
18772
18753
|
var CONSTANTS = {
|
|
18773
|
-
cliVersion: "1.2.
|
|
18754
|
+
cliVersion: "1.2.11",
|
|
18774
18755
|
backendVersion: 1,
|
|
18775
18756
|
backendPort: 5088,
|
|
18776
18757
|
workerVersion: 2,
|
|
@@ -18816,10 +18797,10 @@ var ExecutorScopeClass = class {
|
|
|
18816
18797
|
constructor() {
|
|
18817
18798
|
this.WORKERS_FOLDER = "workers";
|
|
18818
18799
|
this.PRODUCERS_FOLDER = "producers";
|
|
18800
|
+
this.getBasePath = () => import_path3.default.join(Constants_default.defaults.REMORA_PATH, Constants_default.defaults.PRODUCER_TEMP_FOLDER);
|
|
18819
18801
|
this.getWorkerPath = (scope, workerId) => {
|
|
18820
18802
|
return import_path3.default.join(
|
|
18821
|
-
|
|
18822
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
18803
|
+
this.getBasePath(),
|
|
18823
18804
|
// A specific execution sits entirely in this folder, so at the end it's safe to delete it entirely
|
|
18824
18805
|
scope.folder,
|
|
18825
18806
|
this.WORKERS_FOLDER,
|
|
@@ -18828,8 +18809,7 @@ var ExecutorScopeClass = class {
|
|
|
18828
18809
|
};
|
|
18829
18810
|
this.getProducerPath = (scope, producer, sourceFileKey) => {
|
|
18830
18811
|
return import_path3.default.join(
|
|
18831
|
-
|
|
18832
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
18812
|
+
this.getBasePath(),
|
|
18833
18813
|
// A specific execution sits entirely in this folder, so at the end it's safe to delete it entirely
|
|
18834
18814
|
scope.folder,
|
|
18835
18815
|
this.PRODUCERS_FOLDER,
|
|
@@ -18839,22 +18819,30 @@ var ExecutorScopeClass = class {
|
|
|
18839
18819
|
};
|
|
18840
18820
|
this.getMainPath = (scope) => {
|
|
18841
18821
|
return import_path3.default.join(
|
|
18842
|
-
|
|
18843
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
18822
|
+
this.getBasePath(),
|
|
18844
18823
|
scope.folder,
|
|
18845
18824
|
"main.dataset"
|
|
18846
18825
|
);
|
|
18847
18826
|
};
|
|
18848
18827
|
this.clearScope = async (scope) => {
|
|
18849
18828
|
const scopePath = import_path3.default.join(
|
|
18850
|
-
|
|
18851
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
18829
|
+
this.getBasePath(),
|
|
18852
18830
|
scope.folder
|
|
18853
18831
|
);
|
|
18854
18832
|
if (import_fs3.default.existsSync(scopePath)) {
|
|
18855
18833
|
await import_promises.default.rm(scopePath, { recursive: true, force: true });
|
|
18856
18834
|
}
|
|
18857
18835
|
};
|
|
18836
|
+
this.deepClear = () => {
|
|
18837
|
+
const basePath = this.getBasePath();
|
|
18838
|
+
const openScopes = this.getOpenScopes();
|
|
18839
|
+
for (const scopeFolder of openScopes) {
|
|
18840
|
+
const scopePath = import_path3.default.join(basePath, scopeFolder);
|
|
18841
|
+
if (import_fs3.default.existsSync(scopePath)) {
|
|
18842
|
+
import_fs3.default.rmSync(scopePath, { recursive: true, force: true });
|
|
18843
|
+
}
|
|
18844
|
+
}
|
|
18845
|
+
};
|
|
18858
18846
|
this.ensurePath = (fileUri) => {
|
|
18859
18847
|
const dir = import_path3.default.dirname(fileUri);
|
|
18860
18848
|
if (!import_fs3.default.existsSync(dir))
|
|
@@ -18862,11 +18850,106 @@ var ExecutorScopeClass = class {
|
|
|
18862
18850
|
if (!import_fs3.default.existsSync(fileUri))
|
|
18863
18851
|
import_fs3.default.writeFileSync(fileUri, "");
|
|
18864
18852
|
};
|
|
18853
|
+
this.getOpenScopes = () => {
|
|
18854
|
+
const basePath = this.getBasePath();
|
|
18855
|
+
if (!import_fs3.default.existsSync(basePath))
|
|
18856
|
+
return [];
|
|
18857
|
+
return import_fs3.default.readdirSync(basePath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((folder) => folder !== "logs" && folder !== "usage");
|
|
18858
|
+
};
|
|
18865
18859
|
}
|
|
18866
18860
|
};
|
|
18867
18861
|
var ExecutorScope = new ExecutorScopeClass();
|
|
18868
18862
|
var ExecutorScope_default = ExecutorScope;
|
|
18869
18863
|
|
|
18864
|
+
// ../../packages/common/src/ProcessShutdownManager.ts
|
|
18865
|
+
var ProcessShutdownManagerClass = class {
|
|
18866
|
+
constructor() {
|
|
18867
|
+
this._initialized = false;
|
|
18868
|
+
this._cleaned = false;
|
|
18869
|
+
this._runtimeName = "Remora process";
|
|
18870
|
+
this.init = (runtimeName) => {
|
|
18871
|
+
if (this._initialized)
|
|
18872
|
+
return;
|
|
18873
|
+
this._initialized = true;
|
|
18874
|
+
if (runtimeName)
|
|
18875
|
+
this._runtimeName = runtimeName;
|
|
18876
|
+
process.once("SIGINT", () => this.handleSignal("SIGINT", 130));
|
|
18877
|
+
process.once("SIGTERM", () => this.handleSignal("SIGTERM", 143));
|
|
18878
|
+
process.once("uncaughtException", (error) => this.handleUnexpectedShutdown("uncaughtException", error));
|
|
18879
|
+
process.once("unhandledRejection", (reason) => this.handleUnexpectedShutdown("unhandledRejection", reason));
|
|
18880
|
+
process.once("beforeExit", (code) => this.handleBeforeExit(code));
|
|
18881
|
+
process.once("exit", (code) => this.handleExit(code));
|
|
18882
|
+
};
|
|
18883
|
+
this.handleSignal = (signal, exitCode) => {
|
|
18884
|
+
this.setShutdownState("intentional", signal);
|
|
18885
|
+
Logger_default.warn(`Received ${signal}. Shutting down ${this._runtimeName}.`);
|
|
18886
|
+
process.exit(exitCode);
|
|
18887
|
+
};
|
|
18888
|
+
this.handleUnexpectedShutdown = (reason, error) => {
|
|
18889
|
+
this.setShutdownState("unintentional", reason);
|
|
18890
|
+
Logger_default.error(this.asError(reason, error));
|
|
18891
|
+
process.exit(1);
|
|
18892
|
+
};
|
|
18893
|
+
this.handleBeforeExit = (code) => {
|
|
18894
|
+
this.setShutdownState(code === 0 ? "intentional" : "unintentional", `beforeExit:${code}`);
|
|
18895
|
+
};
|
|
18896
|
+
this.handleExit = (code) => {
|
|
18897
|
+
if (!this._shutdownState)
|
|
18898
|
+
this.setShutdownState(code === 0 ? "intentional" : "unintentional", `exit:${code}`);
|
|
18899
|
+
this.cleanupOpenScopes(code);
|
|
18900
|
+
};
|
|
18901
|
+
this.cleanupOpenScopes = (code) => {
|
|
18902
|
+
if (this._cleaned)
|
|
18903
|
+
return;
|
|
18904
|
+
this._cleaned = true;
|
|
18905
|
+
const openScopes = ExecutorScope_default.getOpenScopes();
|
|
18906
|
+
const scopeCount = openScopes.length;
|
|
18907
|
+
const shutdownState = this._shutdownState;
|
|
18908
|
+
const shutdownDescription = `${shutdownState?.type ?? "intentional"} shutdown (${shutdownState?.reason ?? `exit:${code}`})`;
|
|
18909
|
+
if (scopeCount === 0) {
|
|
18910
|
+
Logger_default.info(`Detected ${shutdownDescription} for ${this._runtimeName}. No executor scopes to clean up.`);
|
|
18911
|
+
return;
|
|
18912
|
+
}
|
|
18913
|
+
Logger_default.warn(`Detected ${shutdownDescription} for ${this._runtimeName}. Cleaning up ${scopeCount} executor scope${scopeCount === 1 ? "" : "s"}.`);
|
|
18914
|
+
ExecutorScope_default.deepClear();
|
|
18915
|
+
};
|
|
18916
|
+
this.setShutdownState = (type, reason) => {
|
|
18917
|
+
if (this._shutdownState)
|
|
18918
|
+
return;
|
|
18919
|
+
this._shutdownState = { type, reason };
|
|
18920
|
+
};
|
|
18921
|
+
this.asError = (reason, error) => {
|
|
18922
|
+
if (error instanceof Error) {
|
|
18923
|
+
const contextualError = new Error(`Unexpected ${reason} during ${this._runtimeName} execution: ${error.message}`);
|
|
18924
|
+
contextualError.stack = error.stack;
|
|
18925
|
+
return contextualError;
|
|
18926
|
+
}
|
|
18927
|
+
return new Error(`Unexpected ${reason} during ${this._runtimeName} execution: ${String(error)}`);
|
|
18928
|
+
};
|
|
18929
|
+
}
|
|
18930
|
+
};
|
|
18931
|
+
var ProcessShutdownManager = new ProcessShutdownManagerClass();
|
|
18932
|
+
var ProcessShutdownManager_default = ProcessShutdownManager;
|
|
18933
|
+
|
|
18934
|
+
// ../../packages/common/src/SecretManager.ts
|
|
18935
|
+
var SecretManagerClass = class {
|
|
18936
|
+
constructor() {
|
|
18937
|
+
/**
|
|
18938
|
+
* If the value is a secret (or .env setting), replace it with the value inside the .env configuration file
|
|
18939
|
+
* Starts with "{" and ends with "}".
|
|
18940
|
+
* e.g. {AWS_ID}
|
|
18941
|
+
*/
|
|
18942
|
+
this.replaceSecret = (value) => {
|
|
18943
|
+
if (!value || value.length <= 2 || !value.startsWith("{") || !value.endsWith("}"))
|
|
18944
|
+
return value;
|
|
18945
|
+
const parsedValue = value.slice(1, value.length - 1);
|
|
18946
|
+
return ProcessENVManager_default.getEnvVariable(parsedValue);
|
|
18947
|
+
};
|
|
18948
|
+
}
|
|
18949
|
+
};
|
|
18950
|
+
var SecretManager = new SecretManagerClass();
|
|
18951
|
+
var SecretManager_default = SecretManager;
|
|
18952
|
+
|
|
18870
18953
|
// ../../packages/common/src/Environment.ts
|
|
18871
18954
|
var import_fs5 = __toESM(require("fs"), 1);
|
|
18872
18955
|
var import_crypto = __toESM(require("crypto"), 1);
|
|
@@ -19108,7 +19191,16 @@ var ValidatorClass = class {
|
|
|
19108
19191
|
}
|
|
19109
19192
|
const allAvailableFields = [...availableFieldsByProducer.values()].flat();
|
|
19110
19193
|
for (const field of consumer.fields) {
|
|
19111
|
-
|
|
19194
|
+
const syntheticFieldModes = [field.fixed === true, !!field.copyFrom, field.lineCount === true].filter(Boolean);
|
|
19195
|
+
if (syntheticFieldModes.length > 1)
|
|
19196
|
+
errors.push(`Field "${field.alias ?? field.key}" in consumer "${consumer.name}" can only use one synthetic field mode among "fixed", "copyFrom", and "lineCount".`);
|
|
19197
|
+
if (field.lineCount && field.key === "*")
|
|
19198
|
+
errors.push(`Field "${field.alias ?? field.key}" in consumer "${consumer.name}" cannot use "lineCount" with the wildcard key "*".`);
|
|
19199
|
+
if (field.lineCount && field.transform)
|
|
19200
|
+
errors.push(`Field "${field.alias ?? field.key}" in consumer "${consumer.name}" cannot use "transform" together with "lineCount".`);
|
|
19201
|
+
if (field.lineCount && field.validate && field.validate.length > 0)
|
|
19202
|
+
errors.push(`Field "${field.alias ?? field.key}" in consumer "${consumer.name}" cannot use "validate" together with "lineCount".`);
|
|
19203
|
+
if (field.key === "*" || field.fixed || field.copyFrom || field.lineCount) continue;
|
|
19112
19204
|
if (field.from) {
|
|
19113
19205
|
const producerFields = availableFieldsByProducer.get(field.from);
|
|
19114
19206
|
if (producerFields && !producerFields.includes(field.key))
|
|
@@ -19129,6 +19221,8 @@ var ValidatorClass = class {
|
|
|
19129
19221
|
const found = precedingFields.find((f) => (f.alias ?? f.key) === field.copyFrom);
|
|
19130
19222
|
if (!found)
|
|
19131
19223
|
errors.push(`Field "${field.alias ?? field.key}" uses copyFrom "${field.copyFrom}" but no field with that name/alias exists before it in consumer "${consumer.name}".`);
|
|
19224
|
+
else if (found.lineCount)
|
|
19225
|
+
errors.push(`Field "${field.alias ?? field.key}" in consumer "${consumer.name}" cannot use copyFrom on a field with "lineCount" because line counts are normalized after worker merge.`);
|
|
19132
19226
|
}
|
|
19133
19227
|
if (consumer.filters && consumer.filters.length > 0) {
|
|
19134
19228
|
if (consumer.filters.some((x) => x.sql && x.rule))
|
|
@@ -19149,10 +19243,14 @@ var ValidatorClass = class {
|
|
|
19149
19243
|
const missingRules = rulesWithMatchingFields.filter((x) => !x.match);
|
|
19150
19244
|
errors.push(`Filter(s) on member(s) "${missingRules.map((x) => x.rule.rule.member).join(", ")}" is invalid since the member specified is not present in the consumer. Check the member value or add the missing field to the consumer.`);
|
|
19151
19245
|
}
|
|
19246
|
+
const lineCountRuleMembers = rulesWithMatchingFields.filter((x) => x.match?.lineCount);
|
|
19247
|
+
if (lineCountRuleMembers.length > 0)
|
|
19248
|
+
errors.push(`Consumer "${consumer.name}" cannot use rule-based filters on field(s) with "lineCount": ${lineCountRuleMembers.map((x) => `"${x.rule.rule.member}"`).join(", ")}.`);
|
|
19152
19249
|
}
|
|
19153
19250
|
const validateTransformations = (fields) => {
|
|
19154
19251
|
const errors2 = [];
|
|
19155
19252
|
const trxsFields = fields.filter((x) => x.transform);
|
|
19253
|
+
const lineCountFieldNames = new Set(fields.filter((x) => x.lineCount).map((x) => x.alias ?? x.key));
|
|
19156
19254
|
for (const field of trxsFields) {
|
|
19157
19255
|
const trxToValidate = [];
|
|
19158
19256
|
if (Array.isArray(field.transform))
|
|
@@ -19160,6 +19258,16 @@ var ValidatorClass = class {
|
|
|
19160
19258
|
else
|
|
19161
19259
|
trxToValidate.push(field.transform);
|
|
19162
19260
|
for (const trans of trxToValidate) {
|
|
19261
|
+
if ("multiplyBy" in trans) {
|
|
19262
|
+
const invalidFields = trans.multiplyBy.fields.filter((x) => lineCountFieldNames.has(x));
|
|
19263
|
+
if (invalidFields.length > 0)
|
|
19264
|
+
errors2.push(`Transformation on field "${field.alias ?? field.key}" cannot reference lineCount field(s) in multiplyBy: ${invalidFields.map((x) => `"${x}"`).join(", ")}.`);
|
|
19265
|
+
}
|
|
19266
|
+
if ("addBy" in trans) {
|
|
19267
|
+
const invalidFields = trans.addBy.fields.filter((x) => lineCountFieldNames.has(x));
|
|
19268
|
+
if (invalidFields.length > 0)
|
|
19269
|
+
errors2.push(`Transformation on field "${field.alias ?? field.key}" cannot reference lineCount field(s) in addBy: ${invalidFields.map((x) => `"${x}"`).join(", ")}.`);
|
|
19270
|
+
}
|
|
19163
19271
|
if ("combine_fields" in trans) {
|
|
19164
19272
|
const { combine_fields } = trans;
|
|
19165
19273
|
if (!combine_fields.fields || combine_fields.fields.length === 0)
|
|
@@ -19167,6 +19275,9 @@ var ValidatorClass = class {
|
|
|
19167
19275
|
const missingFieldsInConsumer = combine_fields.fields.map((x) => ({ field: x, found: fields.find((k) => (k.alias ?? k.key) === x) })).filter((x) => !x.found);
|
|
19168
19276
|
if (missingFieldsInConsumer.length > 0)
|
|
19169
19277
|
errors2.push(`The requested field(s) for a transformation is missing in the consumer -> missing field(s): "${missingFieldsInConsumer.map((x) => x.field).join(", ")}"; field transformation: "${field.alias ?? field.key}";`);
|
|
19278
|
+
const invalidFields = combine_fields.fields.filter((x) => lineCountFieldNames.has(x));
|
|
19279
|
+
if (invalidFields.length > 0)
|
|
19280
|
+
errors2.push(`Transformation on field "${field.alias ?? field.key}" cannot reference lineCount field(s) in combine_fields: ${invalidFields.map((x) => `"${x}"`).join(", ")}.`);
|
|
19170
19281
|
}
|
|
19171
19282
|
}
|
|
19172
19283
|
}
|
|
@@ -19189,7 +19300,7 @@ var ValidatorClass = class {
|
|
|
19189
19300
|
errors.push(`The export destination "${output.exportDestination}" was not found in the sources.`);
|
|
19190
19301
|
}
|
|
19191
19302
|
}
|
|
19192
|
-
const dimensionFields = consumer.fields.filter((x) => x.key !== "*" && !x.fixed && !x.copyFrom);
|
|
19303
|
+
const dimensionFields = consumer.fields.filter((x) => x.key !== "*" && !x.fixed && !x.copyFrom && !x.lineCount);
|
|
19193
19304
|
const dimensionKeys = dimensionFields.map((x) => `${x.from ?? "_default_"}::${x.key}`);
|
|
19194
19305
|
const duplicateDimensionKeys = dimensionKeys.filter((k, i) => dimensionKeys.indexOf(k) !== i);
|
|
19195
19306
|
if (duplicateDimensionKeys.length > 0) {
|
|
@@ -20514,6 +20625,19 @@ var Helper = {
|
|
|
20514
20625
|
};
|
|
20515
20626
|
var Helper_default = Helper;
|
|
20516
20627
|
|
|
20628
|
+
// ../../packages/helper/src/Formatter.ts
|
|
20629
|
+
var Formatter = {
|
|
20630
|
+
bytes: (bytes, decimals = 2) => {
|
|
20631
|
+
if (!+bytes) return "0 Bytes";
|
|
20632
|
+
const k = 1024;
|
|
20633
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
20634
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
20635
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
20636
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
20637
|
+
}
|
|
20638
|
+
};
|
|
20639
|
+
var Formatter_default = Formatter;
|
|
20640
|
+
|
|
20517
20641
|
// ../../packages/helper/src/Settings.ts
|
|
20518
20642
|
var SETTINGS = {
|
|
20519
20643
|
db: {
|
|
@@ -22172,10 +22296,10 @@ var LicenceManager = new LicenceManagerClass();
|
|
|
22172
22296
|
var LicenceManager_default = LicenceManager;
|
|
22173
22297
|
|
|
22174
22298
|
// ../../packages/executors/src/ConsumerExecutor.ts
|
|
22175
|
-
var
|
|
22176
|
-
var
|
|
22299
|
+
var import_path18 = __toESM(require("path"));
|
|
22300
|
+
var import_fs12 = __toESM(require("fs"));
|
|
22177
22301
|
var import_readline6 = __toESM(require("readline"));
|
|
22178
|
-
var
|
|
22302
|
+
var import_promises8 = __toESM(require("fs/promises"));
|
|
22179
22303
|
var import_crypto5 = __toESM(require("crypto"));
|
|
22180
22304
|
|
|
22181
22305
|
// ../../packages/engines/src/CryptoEngine.ts
|
|
@@ -23363,6 +23487,25 @@ var ConsumerManagerClass = class {
|
|
|
23363
23487
|
const expandedFields = convertedFields.flatMap((x) => this.expandField(consumer, x, availableColumns));
|
|
23364
23488
|
return expandedFields;
|
|
23365
23489
|
};
|
|
23490
|
+
this.getLineCountFields = (consumer, visibleOnly = false) => {
|
|
23491
|
+
Affirm_default(consumer, "Invalid consumer");
|
|
23492
|
+
return this.getLineCountFieldsFromExpanded(this.getExpandedFields(consumer), visibleOnly);
|
|
23493
|
+
};
|
|
23494
|
+
this.getLineCountFieldsFromExpanded = (fields, visibleOnly = false) => {
|
|
23495
|
+
Affirm_default(fields, "Invalid consumer fields");
|
|
23496
|
+
return fields.filter((field) => this.isLineCountField(field.cField) && (!visibleOnly || !field.cField.hidden));
|
|
23497
|
+
};
|
|
23498
|
+
this.hasLineCountFields = (consumer, visibleOnly = false) => {
|
|
23499
|
+
return this.getLineCountFields(consumer, visibleOnly).length > 0;
|
|
23500
|
+
};
|
|
23501
|
+
this.isSyntheticField = (field) => {
|
|
23502
|
+
Affirm_default(field, "Invalid field");
|
|
23503
|
+
return field.fixed === true || !!field.copyFrom || this.isLineCountField(field);
|
|
23504
|
+
};
|
|
23505
|
+
this.isLineCountField = (field) => {
|
|
23506
|
+
Affirm_default(field, "Invalid field");
|
|
23507
|
+
return field.lineCount === true;
|
|
23508
|
+
};
|
|
23366
23509
|
this.getAvailableColumns = (consumer) => {
|
|
23367
23510
|
return ResourcesUtils_default.getAvailableColumns(consumer);
|
|
23368
23511
|
};
|
|
@@ -23415,7 +23558,7 @@ var ConsumerManagerClass = class {
|
|
|
23415
23558
|
column = columns.find((x) => x.owner === field.from && x.nameInProducer === field.key);
|
|
23416
23559
|
} else if (consumer.producers.length === 1 && !field.from) {
|
|
23417
23560
|
column = columns.find((x) => x.nameInProducer === field.key);
|
|
23418
|
-
} else if (!
|
|
23561
|
+
} else if (!this.isSyntheticField(field)) {
|
|
23419
23562
|
const matches = columns.filter((x) => x.nameInProducer === field.key);
|
|
23420
23563
|
Affirm_default(matches.length > 0, `Consumer "${consumer.name}" misconfiguration: the field "${field.key}" is not found in any of the included producers (${consumer.producers.map((x) => x.name).join(", ")})`);
|
|
23421
23564
|
if (matches.length === 1) {
|
|
@@ -23426,14 +23569,14 @@ var ConsumerManagerClass = class {
|
|
|
23426
23569
|
column = matches[0];
|
|
23427
23570
|
}
|
|
23428
23571
|
if (!column) {
|
|
23429
|
-
if (field.fixed === true && Algo_default.hasVal(field.default) || field
|
|
23572
|
+
if (field.fixed === true && Algo_default.hasVal(field.default) || this.isSyntheticField(field)) {
|
|
23430
23573
|
column = {
|
|
23431
23574
|
aliasInProducer: field.key,
|
|
23432
23575
|
nameInProducer: field.alias ?? field.key,
|
|
23433
23576
|
consumerAlias: field.alias ?? field.key,
|
|
23434
23577
|
consumerKey: field.key,
|
|
23435
23578
|
owner: field.from,
|
|
23436
|
-
dimension: { name: field.key, type: typeof field.default }
|
|
23579
|
+
dimension: { name: field.key, type: this.isLineCountField(field) ? "number" : typeof field.default }
|
|
23437
23580
|
};
|
|
23438
23581
|
}
|
|
23439
23582
|
}
|
|
@@ -24603,69 +24746,8 @@ var UsageManager = new UsageManagerClass();
|
|
|
24603
24746
|
var UsageManager_default = UsageManager;
|
|
24604
24747
|
|
|
24605
24748
|
// ../../packages/executors/src/OutputExecutor.ts
|
|
24606
|
-
var
|
|
24607
|
-
|
|
24608
|
-
// ../../packages/executors/src/ExecutorScope.ts
|
|
24749
|
+
var fs17 = __toESM(require("fs"));
|
|
24609
24750
|
var import_path17 = __toESM(require("path"));
|
|
24610
|
-
var import_fs12 = __toESM(require("fs"));
|
|
24611
|
-
var import_promises8 = __toESM(require("fs/promises"));
|
|
24612
|
-
var ExecutorScopeClass2 = class {
|
|
24613
|
-
constructor() {
|
|
24614
|
-
this.WORKERS_FOLDER = "workers";
|
|
24615
|
-
this.PRODUCERS_FOLDER = "producers";
|
|
24616
|
-
this.getWorkerPath = (scope, workerId) => {
|
|
24617
|
-
return import_path17.default.join(
|
|
24618
|
-
Constants_default.defaults.REMORA_PATH,
|
|
24619
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
24620
|
-
// A specific execution sits entirely in this folder, so at the end it's safe to delete it entirely
|
|
24621
|
-
scope.folder,
|
|
24622
|
-
this.WORKERS_FOLDER,
|
|
24623
|
-
`${workerId}.dataset`
|
|
24624
|
-
);
|
|
24625
|
-
};
|
|
24626
|
-
this.getProducerPath = (scope, producer, sourceFileKey) => {
|
|
24627
|
-
return import_path17.default.join(
|
|
24628
|
-
Constants_default.defaults.REMORA_PATH,
|
|
24629
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
24630
|
-
// A specific execution sits entirely in this folder, so at the end it's safe to delete it entirely
|
|
24631
|
-
scope.folder,
|
|
24632
|
-
this.PRODUCERS_FOLDER,
|
|
24633
|
-
producer.name,
|
|
24634
|
-
`${sourceFileKey}.dataset`
|
|
24635
|
-
);
|
|
24636
|
-
};
|
|
24637
|
-
this.getMainPath = (scope) => {
|
|
24638
|
-
return import_path17.default.join(
|
|
24639
|
-
Constants_default.defaults.REMORA_PATH,
|
|
24640
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
24641
|
-
scope.folder,
|
|
24642
|
-
"main.dataset"
|
|
24643
|
-
);
|
|
24644
|
-
};
|
|
24645
|
-
this.clearScope = async (scope) => {
|
|
24646
|
-
const scopePath = import_path17.default.join(
|
|
24647
|
-
Constants_default.defaults.REMORA_PATH,
|
|
24648
|
-
Constants_default.defaults.PRODUCER_TEMP_FOLDER,
|
|
24649
|
-
scope.folder
|
|
24650
|
-
);
|
|
24651
|
-
if (import_fs12.default.existsSync(scopePath)) {
|
|
24652
|
-
await import_promises8.default.rm(scopePath, { recursive: true, force: true });
|
|
24653
|
-
}
|
|
24654
|
-
};
|
|
24655
|
-
this.ensurePath = (fileUri) => {
|
|
24656
|
-
const dir = import_path17.default.dirname(fileUri);
|
|
24657
|
-
if (!import_fs12.default.existsSync(dir))
|
|
24658
|
-
import_fs12.default.mkdirSync(dir, { recursive: true });
|
|
24659
|
-
if (!import_fs12.default.existsSync(fileUri))
|
|
24660
|
-
import_fs12.default.writeFileSync(fileUri, "");
|
|
24661
|
-
};
|
|
24662
|
-
}
|
|
24663
|
-
};
|
|
24664
|
-
var ExecutorScope2 = new ExecutorScopeClass2();
|
|
24665
|
-
var ExecutorScope_default2 = ExecutorScope2;
|
|
24666
|
-
|
|
24667
|
-
// ../../packages/executors/src/OutputExecutor.ts
|
|
24668
|
-
var import_path18 = __toESM(require("path"));
|
|
24669
24751
|
var OutputExecutorClass = class {
|
|
24670
24752
|
constructor() {
|
|
24671
24753
|
this._getInternalRecordFormat = (consumer) => {
|
|
@@ -24709,13 +24791,13 @@ var OutputExecutorClass = class {
|
|
|
24709
24791
|
for (const output of consumer.outputs) {
|
|
24710
24792
|
const destination = Environment_default.getSource(output.exportDestination);
|
|
24711
24793
|
const driver = await DriverFactory_default.instantiateDestination(destination);
|
|
24712
|
-
const currentPath =
|
|
24794
|
+
const currentPath = import_path17.default.dirname(ExecutorScope_default.getMainPath(scope));
|
|
24713
24795
|
const destinationName = this._composeFileName(consumer, output, this._getExtension(output));
|
|
24714
24796
|
Logger_default.log(`Exporting consumer "${consumer.name}" to "${output.exportDestination}" as ${output.format} (${destinationName})`);
|
|
24715
|
-
const filenameArray =
|
|
24797
|
+
const filenameArray = fs17.readdirSync(currentPath).filter((filename) => filename.includes(".dataset"));
|
|
24716
24798
|
for (const filename in filenameArray) {
|
|
24717
24799
|
const destinationPath = this.getCompletedPath(destinationName, filename);
|
|
24718
|
-
const startingPath =
|
|
24800
|
+
const startingPath = import_path17.default.join(currentPath, filenameArray[filename]);
|
|
24719
24801
|
if (output.format === internalFormat) {
|
|
24720
24802
|
results.push(await driver.move(startingPath, destinationPath));
|
|
24721
24803
|
} else {
|
|
@@ -24775,47 +24857,54 @@ var OutputExecutor_default = OutputExecutor;
|
|
|
24775
24857
|
var ConsumerExecutorClass = class {
|
|
24776
24858
|
constructor() {
|
|
24777
24859
|
this._getWorkPath = (consumer, executionId) => {
|
|
24778
|
-
const execFolder =
|
|
24779
|
-
const workPath =
|
|
24860
|
+
const execFolder = import_path18.default.join(consumer.name, executionId);
|
|
24861
|
+
const workPath = import_path18.default.join("./remora", Constants_default.defaults.PRODUCER_TEMP_FOLDER, execFolder, ".dataset");
|
|
24780
24862
|
return workPath;
|
|
24781
24863
|
};
|
|
24782
24864
|
this._clearWorkPath = async (workPath) => {
|
|
24783
24865
|
try {
|
|
24784
|
-
if (
|
|
24785
|
-
await
|
|
24866
|
+
if (import_fs12.default.existsSync(workPath)) {
|
|
24867
|
+
await import_promises8.default.unlink(workPath);
|
|
24786
24868
|
}
|
|
24787
24869
|
} catch (error) {
|
|
24788
24870
|
}
|
|
24789
24871
|
try {
|
|
24790
|
-
const dir =
|
|
24791
|
-
if (
|
|
24792
|
-
await
|
|
24872
|
+
const dir = import_path18.default.dirname(workPath);
|
|
24873
|
+
if (import_fs12.default.existsSync(dir)) {
|
|
24874
|
+
await import_promises8.default.rmdir(dir);
|
|
24793
24875
|
}
|
|
24794
24876
|
} catch (error) {
|
|
24795
24877
|
}
|
|
24796
24878
|
};
|
|
24797
24879
|
this._ensurePath = (pathUri) => {
|
|
24798
|
-
const dir =
|
|
24799
|
-
if (!
|
|
24800
|
-
|
|
24801
|
-
if (!
|
|
24802
|
-
|
|
24880
|
+
const dir = import_path18.default.dirname(pathUri);
|
|
24881
|
+
if (!import_fs12.default.existsSync(dir))
|
|
24882
|
+
import_fs12.default.mkdirSync(dir, { recursive: true });
|
|
24883
|
+
if (!import_fs12.default.existsSync(pathUri))
|
|
24884
|
+
import_fs12.default.writeFileSync(pathUri, "");
|
|
24803
24885
|
};
|
|
24804
24886
|
this.processRecord = (options) => {
|
|
24805
24887
|
const { consumer, fields, dimensions, producer, record, requestOptions, index: recordIndex } = options;
|
|
24806
24888
|
for (const field of fields) {
|
|
24807
24889
|
const { cField } = field;
|
|
24808
24890
|
const fieldKey = cField.alias ?? cField.key;
|
|
24891
|
+
if (cField.fixed && Algo_default.hasVal(cField.default)) {
|
|
24892
|
+
record[fieldKey] = cField.default;
|
|
24893
|
+
continue;
|
|
24894
|
+
}
|
|
24895
|
+
if (ConsumerManager_default.isLineCountField(cField)) {
|
|
24896
|
+
record[fieldKey] = recordIndex + 1;
|
|
24897
|
+
continue;
|
|
24898
|
+
}
|
|
24899
|
+
if (cField.copyFrom) {
|
|
24900
|
+
record[fieldKey] = record[cField.copyFrom];
|
|
24901
|
+
continue;
|
|
24902
|
+
}
|
|
24809
24903
|
let dimension;
|
|
24810
24904
|
try {
|
|
24811
24905
|
dimension = dimensions.find((x) => x.name === cField.key);
|
|
24812
24906
|
if (!dimension) {
|
|
24813
|
-
|
|
24814
|
-
record[fieldKey] = cField.default;
|
|
24815
|
-
else if (cField.copyFrom)
|
|
24816
|
-
record[fieldKey] = record[cField.copyFrom];
|
|
24817
|
-
else
|
|
24818
|
-
throw new Error(`The requested field "${cField.key}" from the consumer is not present in the underlying producer "${producer.name}" (${dimensions.map((x) => x.name).join(", ")})`);
|
|
24907
|
+
throw new Error(`The requested field "${cField.key}" from the consumer is not present in the underlying producer "${producer.name}" (${dimensions.map((x) => x.name).join(", ")})`);
|
|
24819
24908
|
}
|
|
24820
24909
|
} catch (error) {
|
|
24821
24910
|
const err2 = new Error(`Resolving dimension for field "${fieldKey}" of producer "${producer.name}" failed (index: ${recordIndex}): ${error.message}`, { cause: error });
|
|
@@ -24928,11 +25017,69 @@ var ConsumerExecutorClass = class {
|
|
|
24928
25017
|
}
|
|
24929
25018
|
return record;
|
|
24930
25019
|
};
|
|
25020
|
+
this.processLineCount = async (consumer, datasetPath, executorResults) => {
|
|
25021
|
+
const internalRecordFormat = OutputExecutor_default._getInternalRecordFormat(consumer);
|
|
25022
|
+
const internalFields = ConsumerManager_default.getExpandedFields(consumer);
|
|
25023
|
+
const lineCountFields = ConsumerManager_default.getLineCountFieldsFromExpanded(internalFields, true);
|
|
25024
|
+
if (lineCountFields.length === 0)
|
|
25025
|
+
return 0;
|
|
25026
|
+
const tempWorkPath = datasetPath + "_tmp";
|
|
25027
|
+
const reader = import_fs12.default.createReadStream(datasetPath);
|
|
25028
|
+
const lineReader = import_readline6.default.createInterface({ input: reader, crlfDelay: Infinity });
|
|
25029
|
+
const writer = import_fs12.default.createWriteStream(tempWorkPath);
|
|
25030
|
+
const waitForDrain = () => new Promise((resolve) => writer.once("drain", resolve));
|
|
25031
|
+
let workerIndex = 0;
|
|
25032
|
+
let currentWorker = executorResults[workerIndex] ?? null;
|
|
25033
|
+
let remainingLinesInWorker = currentWorker?.outputCount ?? 0;
|
|
25034
|
+
let processedLineCount = 0;
|
|
25035
|
+
const advanceWorker = () => {
|
|
25036
|
+
while (currentWorker && remainingLinesInWorker <= 0) {
|
|
25037
|
+
workerIndex++;
|
|
25038
|
+
currentWorker = executorResults[workerIndex] ?? null;
|
|
25039
|
+
remainingLinesInWorker = currentWorker?.outputCount ?? 0;
|
|
25040
|
+
}
|
|
25041
|
+
};
|
|
25042
|
+
advanceWorker();
|
|
25043
|
+
for await (const line of lineReader) {
|
|
25044
|
+
advanceWorker();
|
|
25045
|
+
Affirm_default(currentWorker, `Unable to resolve worker metadata while processing lineCount for ${datasetPath}`);
|
|
25046
|
+
const rowOffset = currentWorker.rowOffset ?? 0;
|
|
25047
|
+
if (rowOffset > 0) {
|
|
25048
|
+
const record = this._parseLine(line, internalRecordFormat, internalFields);
|
|
25049
|
+
for (const field of lineCountFields) {
|
|
25050
|
+
const currentValue = Number(record[field.finalKey]);
|
|
25051
|
+
Affirm_default(!Number.isNaN(currentValue), `Invalid lineCount value found while processing ${datasetPath}`);
|
|
25052
|
+
record[field.finalKey] = currentValue + rowOffset;
|
|
25053
|
+
}
|
|
25054
|
+
if (!writer.write(OutputExecutor_default.outputRecord(record, consumer, internalFields) + "\n"))
|
|
25055
|
+
await waitForDrain();
|
|
25056
|
+
} else if (!writer.write(line + "\n")) {
|
|
25057
|
+
await waitForDrain();
|
|
25058
|
+
}
|
|
25059
|
+
remainingLinesInWorker--;
|
|
25060
|
+
processedLineCount++;
|
|
25061
|
+
}
|
|
25062
|
+
lineReader.close();
|
|
25063
|
+
await new Promise((resolve, reject) => {
|
|
25064
|
+
writer.on("close", resolve);
|
|
25065
|
+
writer.on("error", reject);
|
|
25066
|
+
writer.end();
|
|
25067
|
+
});
|
|
25068
|
+
if (!reader.destroyed) {
|
|
25069
|
+
await new Promise((resolve) => {
|
|
25070
|
+
reader.once("close", resolve);
|
|
25071
|
+
reader.destroy();
|
|
25072
|
+
});
|
|
25073
|
+
}
|
|
25074
|
+
await import_promises8.default.unlink(datasetPath);
|
|
25075
|
+
await import_promises8.default.rename(tempWorkPath, datasetPath);
|
|
25076
|
+
return processedLineCount;
|
|
25077
|
+
};
|
|
24931
25078
|
this.processDistinct = async (datasetPath) => {
|
|
24932
|
-
const reader =
|
|
25079
|
+
const reader = import_fs12.default.createReadStream(datasetPath);
|
|
24933
25080
|
const lineReader = import_readline6.default.createInterface({ input: reader, crlfDelay: Infinity });
|
|
24934
25081
|
const tempWorkPath = datasetPath + "_tmp";
|
|
24935
|
-
const writer =
|
|
25082
|
+
const writer = import_fs12.default.createWriteStream(tempWorkPath);
|
|
24936
25083
|
const waitForDrain = () => new Promise((resolve) => writer.once("drain", resolve));
|
|
24937
25084
|
let newLineCount = 0;
|
|
24938
25085
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -24957,12 +25104,12 @@ var ConsumerExecutorClass = class {
|
|
|
24957
25104
|
reader.destroy();
|
|
24958
25105
|
});
|
|
24959
25106
|
}
|
|
24960
|
-
await
|
|
24961
|
-
await
|
|
25107
|
+
await import_promises8.default.unlink(datasetPath);
|
|
25108
|
+
await import_promises8.default.rename(tempWorkPath, datasetPath);
|
|
24962
25109
|
return newLineCount;
|
|
24963
25110
|
};
|
|
24964
25111
|
this.processDistinctOn = async (consumer, datasetPath) => {
|
|
24965
|
-
const reader =
|
|
25112
|
+
const reader = import_fs12.default.createReadStream(datasetPath);
|
|
24966
25113
|
const lineReader = import_readline6.default.createInterface({ input: reader, crlfDelay: Infinity });
|
|
24967
25114
|
const { distinctOn } = consumer.options;
|
|
24968
25115
|
const { keys, resolution } = distinctOn;
|
|
@@ -24985,7 +25132,7 @@ var ConsumerExecutorClass = class {
|
|
|
24985
25132
|
}
|
|
24986
25133
|
lineReader.close();
|
|
24987
25134
|
const tempWorkPath = datasetPath + "_tmp";
|
|
24988
|
-
const writer =
|
|
25135
|
+
const writer = import_fs12.default.createWriteStream(tempWorkPath);
|
|
24989
25136
|
const waitForDrain = () => new Promise((resolve) => writer.once("drain", resolve));
|
|
24990
25137
|
for (const { line } of winners.values()) {
|
|
24991
25138
|
if (!writer.write(line + "\n"))
|
|
@@ -25002,8 +25149,8 @@ var ConsumerExecutorClass = class {
|
|
|
25002
25149
|
reader.destroy();
|
|
25003
25150
|
});
|
|
25004
25151
|
}
|
|
25005
|
-
await
|
|
25006
|
-
await
|
|
25152
|
+
await import_promises8.default.unlink(datasetPath);
|
|
25153
|
+
await import_promises8.default.rename(tempWorkPath, datasetPath);
|
|
25007
25154
|
return winners.size;
|
|
25008
25155
|
};
|
|
25009
25156
|
this.processPivot = async (consumer, datasetPath) => {
|
|
@@ -25015,7 +25162,7 @@ var ConsumerExecutorClass = class {
|
|
|
25015
25162
|
if (!pivotValues) {
|
|
25016
25163
|
pivotValues = [];
|
|
25017
25164
|
const discoverySet = /* @__PURE__ */ new Set();
|
|
25018
|
-
const discoverReader =
|
|
25165
|
+
const discoverReader = import_fs12.default.createReadStream(datasetPath);
|
|
25019
25166
|
const discoverLineReader = import_readline6.default.createInterface({ input: discoverReader, crlfDelay: Infinity });
|
|
25020
25167
|
for await (const line of discoverLineReader) {
|
|
25021
25168
|
const record = this._parseLine(line, internalRecordFormat, internalFields);
|
|
@@ -25034,7 +25181,7 @@ var ConsumerExecutorClass = class {
|
|
|
25034
25181
|
}
|
|
25035
25182
|
}
|
|
25036
25183
|
const groups = /* @__PURE__ */ new Map();
|
|
25037
|
-
const reader =
|
|
25184
|
+
const reader = import_fs12.default.createReadStream(datasetPath);
|
|
25038
25185
|
const lineReader = import_readline6.default.createInterface({ input: reader, crlfDelay: Infinity });
|
|
25039
25186
|
for await (const line of lineReader) {
|
|
25040
25187
|
const record = this._parseLine(line, internalRecordFormat, internalFields);
|
|
@@ -25062,7 +25209,7 @@ var ConsumerExecutorClass = class {
|
|
|
25062
25209
|
...pivotValues.map((pv) => ({ cField: { key: columnPrefix + pv }, finalKey: columnPrefix + pv }))
|
|
25063
25210
|
];
|
|
25064
25211
|
const tempWorkPath = datasetPath + "_tmp";
|
|
25065
|
-
const writer =
|
|
25212
|
+
const writer = import_fs12.default.createWriteStream(tempWorkPath);
|
|
25066
25213
|
const waitForDrain = () => new Promise((resolve) => writer.once("drain", resolve));
|
|
25067
25214
|
let outputCount = 0;
|
|
25068
25215
|
for (const { rowRecord, cells } of groups.values()) {
|
|
@@ -25108,8 +25255,8 @@ var ConsumerExecutorClass = class {
|
|
|
25108
25255
|
reader.destroy();
|
|
25109
25256
|
});
|
|
25110
25257
|
}
|
|
25111
|
-
await
|
|
25112
|
-
await
|
|
25258
|
+
await import_promises8.default.unlink(datasetPath);
|
|
25259
|
+
await import_promises8.default.rename(tempWorkPath, datasetPath);
|
|
25113
25260
|
return outputCount;
|
|
25114
25261
|
};
|
|
25115
25262
|
this._parseLine = (line, format2, fields) => {
|
|
@@ -25155,7 +25302,7 @@ var ConsumerExecutorClass = class {
|
|
|
25155
25302
|
for (const fieldKey of uniqueFieldKeys) {
|
|
25156
25303
|
fieldValueSets.set(fieldKey, /* @__PURE__ */ new Set());
|
|
25157
25304
|
}
|
|
25158
|
-
const reader =
|
|
25305
|
+
const reader = import_fs12.default.createReadStream(datasetPath);
|
|
25159
25306
|
const lineReader = import_readline6.default.createInterface({ input: reader, crlfDelay: Infinity });
|
|
25160
25307
|
for await (const line of lineReader) {
|
|
25161
25308
|
rowCount++;
|
|
@@ -25203,7 +25350,7 @@ var ConsumerExecutor = new ConsumerExecutorClass();
|
|
|
25203
25350
|
var ConsumerExecutor_default = ConsumerExecutor;
|
|
25204
25351
|
|
|
25205
25352
|
// ../../packages/executors/src/ProducerExecutor.ts
|
|
25206
|
-
var
|
|
25353
|
+
var import_path19 = __toESM(require("path"));
|
|
25207
25354
|
var ProducerExecutorClass = class {
|
|
25208
25355
|
constructor() {
|
|
25209
25356
|
this.ready = async (producer, scope) => {
|
|
@@ -25229,7 +25376,7 @@ var ProducerExecutorClass = class {
|
|
|
25229
25376
|
counter = performance.now();
|
|
25230
25377
|
for (const dimension of dimensions) {
|
|
25231
25378
|
if (dimension.prodDimension.sourceFilename === true)
|
|
25232
|
-
record[dimension.name] =
|
|
25379
|
+
record[dimension.name] = import_path19.default.basename(chunk.fileUri);
|
|
25233
25380
|
const maskType = ProducerManager_default.getMask(dimension.prodDimension);
|
|
25234
25381
|
if (Algo_default.hasVal(maskType))
|
|
25235
25382
|
record[dimension.name] = CryptoEngine_default.hashValue(maskType, record[dimension.name]?.toString(), dimension.prodDimension.type);
|
|
@@ -25260,14 +25407,13 @@ var ExecutorPerformance = class {
|
|
|
25260
25407
|
var ExecutorPerformance_default = ExecutorPerformance;
|
|
25261
25408
|
|
|
25262
25409
|
// ../../packages/executors/src/ExecutorOrchestrator.ts
|
|
25263
|
-
var
|
|
25264
|
-
var
|
|
25265
|
-
var import_promises10 = __toESM(require("fs/promises"));
|
|
25410
|
+
var import_fs13 = __toESM(require("fs"));
|
|
25411
|
+
var import_promises9 = __toESM(require("fs/promises"));
|
|
25266
25412
|
var import_path21 = __toESM(require("path"));
|
|
25267
25413
|
var import_workerpool = __toESM(require("workerpool"));
|
|
25268
25414
|
|
|
25269
25415
|
// ../../packages/executors/src/ExecutorWriter.ts
|
|
25270
|
-
var
|
|
25416
|
+
var fs19 = __toESM(require("fs"));
|
|
25271
25417
|
var import_readline7 = __toESM(require("readline"));
|
|
25272
25418
|
var ExecutorWriter = class {
|
|
25273
25419
|
constructor() {
|
|
@@ -25284,11 +25430,11 @@ var ExecutorWriter = class {
|
|
|
25284
25430
|
};
|
|
25285
25431
|
this.splitBySize = async (scope, sourcePath) => {
|
|
25286
25432
|
const maxOutputFileSize = scope.limitFileSize * this.FAKE_GB;
|
|
25287
|
-
const readStream =
|
|
25433
|
+
const readStream = fs19.createReadStream(sourcePath);
|
|
25288
25434
|
const reader = import_readline7.default.createInterface({ input: readStream, crlfDelay: Infinity });
|
|
25289
25435
|
let writerIndex = 0;
|
|
25290
25436
|
let destPath = this.getCompletedPath(sourcePath, writerIndex);
|
|
25291
|
-
let writeStream =
|
|
25437
|
+
let writeStream = fs19.createWriteStream(destPath, { flags: "a" });
|
|
25292
25438
|
const waitForDrain = () => new Promise((resolve) => writeStream.once("drain", resolve));
|
|
25293
25439
|
for await (const line of reader) {
|
|
25294
25440
|
if (readStream.bytesRead > maxOutputFileSize * (writerIndex + 1)) {
|
|
@@ -25299,7 +25445,7 @@ var ExecutorWriter = class {
|
|
|
25299
25445
|
});
|
|
25300
25446
|
writerIndex++;
|
|
25301
25447
|
destPath = this.getCompletedPath(sourcePath, writerIndex);
|
|
25302
|
-
writeStream =
|
|
25448
|
+
writeStream = fs19.createWriteStream(destPath, { flags: "a" });
|
|
25303
25449
|
}
|
|
25304
25450
|
if (!writeStream.write(line + "\n"))
|
|
25305
25451
|
await waitForDrain();
|
|
@@ -25309,7 +25455,7 @@ var ExecutorWriter = class {
|
|
|
25309
25455
|
writeStream.on("finish", resolve);
|
|
25310
25456
|
writeStream.on("error", reject);
|
|
25311
25457
|
});
|
|
25312
|
-
await
|
|
25458
|
+
await fs19.promises.unlink(sourcePath);
|
|
25313
25459
|
};
|
|
25314
25460
|
/**
|
|
25315
25461
|
* Manage the Writestream for main.dataset
|
|
@@ -25366,7 +25512,7 @@ var ExecutorWriter = class {
|
|
|
25366
25512
|
var ExecutorWriter_default = ExecutorWriter;
|
|
25367
25513
|
|
|
25368
25514
|
// ../../packages/executors/src/ExecutorOrchestrator.ts
|
|
25369
|
-
var
|
|
25515
|
+
var import_promises10 = require("stream/promises");
|
|
25370
25516
|
|
|
25371
25517
|
// ../../packages/executors/src/cli_progress/ExecutorProgress2.ts
|
|
25372
25518
|
var ExecutorProgress2 = class {
|
|
@@ -25402,19 +25548,111 @@ var ExecutorProgress2 = class {
|
|
|
25402
25548
|
};
|
|
25403
25549
|
var ExecutorProgress2_default = ExecutorProgress2;
|
|
25404
25550
|
|
|
25551
|
+
// ../../packages/executors/src/OrchestratorHelper.ts
|
|
25552
|
+
var import_os = __toESM(require("os"));
|
|
25553
|
+
var import_path20 = __toESM(require("path"));
|
|
25554
|
+
var OrchestratorHelper = {
|
|
25555
|
+
getMemoryUsage: () => {
|
|
25556
|
+
const processMemory = process.memoryUsage();
|
|
25557
|
+
const freeSystemMemory = import_os.default.freemem();
|
|
25558
|
+
return {
|
|
25559
|
+
/**
|
|
25560
|
+
* resident set size (heap + code + stack)
|
|
25561
|
+
*/
|
|
25562
|
+
rss: Formatter_default.bytes(processMemory.rss),
|
|
25563
|
+
heapUsed: Formatter_default.bytes(processMemory.heapUsed),
|
|
25564
|
+
heapTotal: Formatter_default.bytes(processMemory.heapTotal),
|
|
25565
|
+
heapPercent: Algo_default.round(processMemory.heapUsed / processMemory.heapTotal, 1),
|
|
25566
|
+
external: Formatter_default.bytes(processMemory.external),
|
|
25567
|
+
free: Formatter_default.bytes(freeSystemMemory)
|
|
25568
|
+
};
|
|
25569
|
+
},
|
|
25570
|
+
formatMemoryUsage: () => {
|
|
25571
|
+
return `Memory [total: ${OrchestratorHelper.getMemoryUsage().rss} - heap: ${OrchestratorHelper.getMemoryUsage().heapPercent}%]`;
|
|
25572
|
+
},
|
|
25573
|
+
computeFinalResult: (tracker, executorResults, executionId, resultUri) => {
|
|
25574
|
+
const result = {
|
|
25575
|
+
cycles: Algo_default.max(executorResults.map((x) => x.cycles)),
|
|
25576
|
+
elapsedMS: Algo_default.sum(executorResults.map((x) => x.elapsedMS)),
|
|
25577
|
+
inputCount: Algo_default.sum(executorResults.map((x) => x.inputCount)),
|
|
25578
|
+
outputCount: Algo_default.sum(executorResults.map((x) => x.outputCount)),
|
|
25579
|
+
workerCount: executorResults.length,
|
|
25580
|
+
executionId,
|
|
25581
|
+
resultUri,
|
|
25582
|
+
operations: {}
|
|
25583
|
+
};
|
|
25584
|
+
for (const res of executorResults) {
|
|
25585
|
+
for (const opKey of Object.keys(res.operations)) {
|
|
25586
|
+
const op = res.operations[opKey];
|
|
25587
|
+
let label = result.operations[opKey];
|
|
25588
|
+
if (!label) {
|
|
25589
|
+
result.operations[opKey] = { avg: -1, max: -1, min: -1, elapsedMS: [] };
|
|
25590
|
+
label = result.operations[opKey];
|
|
25591
|
+
}
|
|
25592
|
+
label.elapsedMS.push(op.elapsedMS);
|
|
25593
|
+
}
|
|
25594
|
+
for (const opKey of Object.keys(result.operations)) {
|
|
25595
|
+
const operation = result.operations[opKey];
|
|
25596
|
+
if (operation.elapsedMS.length > 0) {
|
|
25597
|
+
operation.min = Math.min(...operation.elapsedMS);
|
|
25598
|
+
operation.max = Math.max(...operation.elapsedMS);
|
|
25599
|
+
operation.avg = Algo_default.mean(operation.elapsedMS);
|
|
25600
|
+
}
|
|
25601
|
+
}
|
|
25602
|
+
}
|
|
25603
|
+
const trackerOperations = tracker.getOperations();
|
|
25604
|
+
for (const opKey of Object.keys(trackerOperations)) {
|
|
25605
|
+
const trackerOp = trackerOperations[opKey];
|
|
25606
|
+
const value = trackerOp.elapsedMS;
|
|
25607
|
+
if (!result.operations[opKey]) {
|
|
25608
|
+
result.operations[opKey] = { avg: value, max: value, min: value, elapsedMS: [] };
|
|
25609
|
+
}
|
|
25610
|
+
result.operations[opKey].elapsedMS.push(value);
|
|
25611
|
+
}
|
|
25612
|
+
return result;
|
|
25613
|
+
},
|
|
25614
|
+
/**
|
|
25615
|
+
* Returns the path to the worker thread file in the build (different between dev, cli and prod (docker)).
|
|
25616
|
+
* IMPORTANT!: when moving this (OrchestratorHelper.ts) file, or the workers output, you have to make sure to update these paths
|
|
25617
|
+
*/
|
|
25618
|
+
getPhysicalWorkerPath: () => {
|
|
25619
|
+
const currentDir = __dirname;
|
|
25620
|
+
if (ProcessENVManager_default.getEnvVariable("NODE_ENV") === "dev" || ProcessENVManager_default.getEnvVariable("NODE_ENV") === "development")
|
|
25621
|
+
return import_path20.default.resolve("./.build/workers");
|
|
25622
|
+
const forcedPath = ProcessENVManager_default.getEnvVariable("REMORA_WORKERS_PATH");
|
|
25623
|
+
if (forcedPath && forcedPath.length > 0)
|
|
25624
|
+
return import_path20.default.join(__dirname, forcedPath);
|
|
25625
|
+
if (!currentDir.includes(".build")) {
|
|
25626
|
+
return import_path20.default.join(__dirname, "../workers");
|
|
25627
|
+
} else {
|
|
25628
|
+
return import_path20.default.resolve("./.build/workers");
|
|
25629
|
+
}
|
|
25630
|
+
},
|
|
25631
|
+
getParallelWorkerCount: () => {
|
|
25632
|
+
const cpuBoundWorkers = Math.max(1, Math.floor(import_os.default.cpus().length * 0.7));
|
|
25633
|
+
const totalMemoryMB = Math.floor(import_os.default.totalmem() / (1024 * 1024));
|
|
25634
|
+
const reservedMemoryMB = Constants_default.defaults.MIN_RUNTIME_HEAP_MB * 2;
|
|
25635
|
+
const availableMemoryForWorkersMB = Math.max(Constants_default.defaults.MIN_RUNTIME_HEAP_MB, totalMemoryMB - reservedMemoryMB);
|
|
25636
|
+
const memoryBoundWorkers = Math.max(1, Math.floor(availableMemoryForWorkersMB / Constants_default.defaults.MIN_RUNTIME_HEAP_MB));
|
|
25637
|
+
return Math.min(cpuBoundWorkers, Constants_default.defaults.MAX_THREAD_COUNT, memoryBoundWorkers);
|
|
25638
|
+
}
|
|
25639
|
+
};
|
|
25640
|
+
var OrchestratorHelper_default = OrchestratorHelper;
|
|
25641
|
+
|
|
25405
25642
|
// ../../packages/executors/src/ExecutorOrchestrator.ts
|
|
25406
25643
|
var ExecutorOrchestratorClass = class {
|
|
25407
25644
|
constructor() {
|
|
25408
|
-
this.createPool = () => {
|
|
25645
|
+
this.createPool = (maxWorkers) => {
|
|
25409
25646
|
const options = {
|
|
25647
|
+
maxWorkers,
|
|
25410
25648
|
workerThreadOpts: {
|
|
25411
25649
|
resourceLimits: {
|
|
25412
25650
|
maxOldGenerationSizeMb: Constants_default.defaults.MIN_RUNTIME_HEAP_MB
|
|
25413
25651
|
}
|
|
25414
25652
|
}
|
|
25415
25653
|
};
|
|
25416
|
-
const workerPath =
|
|
25417
|
-
Logger_default.log(`Initializing worker pool from ${workerPath} (heap limit: ${Constants_default.defaults.MIN_RUNTIME_HEAP_MB}MB)`);
|
|
25654
|
+
const workerPath = OrchestratorHelper_default.getPhysicalWorkerPath();
|
|
25655
|
+
Logger_default.log(`Initializing worker pool from ${workerPath} (workers: ${maxWorkers}, heap limit: ${Constants_default.defaults.MIN_RUNTIME_HEAP_MB}MB) | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25418
25656
|
return import_workerpool.default.pool(import_path21.default.join(workerPath, "ExecutorWorker.js"), options);
|
|
25419
25657
|
};
|
|
25420
25658
|
this.launch = async (request) => {
|
|
@@ -25428,11 +25666,12 @@ var ExecutorOrchestratorClass = class {
|
|
|
25428
25666
|
const _progress = new ExecutorProgress2_default(logProgress);
|
|
25429
25667
|
const { usageId } = UsageManager_default.startUsage(consumer, details);
|
|
25430
25668
|
const scope = { id: usageId, folder: `${consumer.name}_${usageId}`, workersId: [], limitFileSize: consumer.maximumFileSize };
|
|
25431
|
-
const
|
|
25669
|
+
const expandedFields = ConsumerManager_default.getExpandedFields(consumer);
|
|
25670
|
+
let activePool = null;
|
|
25432
25671
|
try {
|
|
25433
25672
|
const start = performance.now();
|
|
25434
25673
|
const executorResults = [];
|
|
25435
|
-
Logger_default.log(`[${usageId}] Launching consumer "${consumer.name}" (invoked by: ${details.invokedBy}, user: ${details.user?.name ?? "unknown"}, producer(s): ${consumer.producers.length})`);
|
|
25674
|
+
Logger_default.log(`[${usageId}] Launching consumer "${consumer.name}" (invoked by: ${details.invokedBy}, user: ${details.user?.name ?? "unknown"}, producer(s): ${consumer.producers.length}) | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25436
25675
|
let counter = performance.now();
|
|
25437
25676
|
_progress.update({ phase: "Preparing source data", progress: 0 });
|
|
25438
25677
|
let sourceFilesByProducer = await this.readySourceFiles(consumer, scope);
|
|
@@ -25448,10 +25687,10 @@ var ExecutorOrchestratorClass = class {
|
|
|
25448
25687
|
let globalWorkerIndex = 0;
|
|
25449
25688
|
for (const pair of sourceFilesByProducer) {
|
|
25450
25689
|
const { prod, cProd, response } = pair;
|
|
25451
|
-
if (!
|
|
25452
|
-
if (!cProd.isOptional)
|
|
25690
|
+
if (!import_fs13.default.existsSync(response.files[0].fullUri)) {
|
|
25691
|
+
if (!cProd.isOptional) {
|
|
25453
25692
|
throw new Error(`Expected data file ${response.files[0].fullUri} of producer ${prod.name} in consumer ${consumer.name} is missing.`);
|
|
25454
|
-
else if (cProd.isOptional === true) {
|
|
25693
|
+
} else if (cProd.isOptional === true) {
|
|
25455
25694
|
Logger_default.log(`[${usageId}] Producer "${prod.name}": data file missing but marked optional, skipping`);
|
|
25456
25695
|
continue;
|
|
25457
25696
|
}
|
|
@@ -25464,35 +25703,42 @@ var ExecutorOrchestratorClass = class {
|
|
|
25464
25703
|
for (const [fileIndex, file] of response.files.entries()) {
|
|
25465
25704
|
const chunks = ExecutorOrchestrator.scopeWork(file.fullUri);
|
|
25466
25705
|
const workerThreads = [];
|
|
25467
|
-
|
|
25468
|
-
|
|
25469
|
-
|
|
25470
|
-
|
|
25471
|
-
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
|
|
25477
|
-
|
|
25478
|
-
|
|
25479
|
-
|
|
25480
|
-
|
|
25481
|
-
|
|
25482
|
-
|
|
25483
|
-
|
|
25484
|
-
|
|
25485
|
-
|
|
25486
|
-
|
|
25487
|
-
|
|
25488
|
-
|
|
25706
|
+
activePool = this.createPool(chunks.length);
|
|
25707
|
+
Logger_default.log(`[${usageId}] Producer "${prod.name}" file ${fileIndex + 1}/${totalFiles}: split into ${chunks.length} chunk(s) | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25708
|
+
try {
|
|
25709
|
+
for (const chunk of chunks) {
|
|
25710
|
+
const workerId = `${usageId}_${globalWorkerIndex}`;
|
|
25711
|
+
globalWorkerIndex++;
|
|
25712
|
+
const workerData = {
|
|
25713
|
+
producer: prod,
|
|
25714
|
+
chunk,
|
|
25715
|
+
consumer,
|
|
25716
|
+
prodDimensions,
|
|
25717
|
+
workerId,
|
|
25718
|
+
scope,
|
|
25719
|
+
options,
|
|
25720
|
+
loggerConfig: Logger_default.getConfig()
|
|
25721
|
+
};
|
|
25722
|
+
scope.workersId.push(workerId);
|
|
25723
|
+
Logger_default.log(`[${usageId}] Spawning worker ${workerId} for producer "${prod.name}" \u2014 chunk ${chunk.start}-${chunk.end} (${Math.round((chunk.end - chunk.start) / 1024)}KB)`);
|
|
25724
|
+
workerThreads.push(activePool.exec("executor", [workerData], {
|
|
25725
|
+
on: (payload) => this.onWorkAdvanced(payload, workerId, _progress, totalBytesToProcess, bytesProcessedByWorker)
|
|
25726
|
+
}).catch((error) => {
|
|
25727
|
+
Logger_default.error(error);
|
|
25728
|
+
return null;
|
|
25729
|
+
}));
|
|
25730
|
+
}
|
|
25731
|
+
Logger_default.log(`[${usageId}] Waiting for ${workerThreads.length} worker(s) to complete | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25732
|
+
const fileExecutorResults = await Promise.all(workerThreads);
|
|
25733
|
+
this.assignChunkRowMetadata(chunks, fileExecutorResults);
|
|
25734
|
+
executorResults.push(...fileExecutorResults);
|
|
25735
|
+
Logger_default.log(`[${usageId}] All ${workerThreads.length} worker(s) finished for producer "${prod.name}" file ${fileIndex + 1}/${totalFiles} | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25736
|
+
} finally {
|
|
25737
|
+
await activePool.terminate();
|
|
25738
|
+
activePool = null;
|
|
25489
25739
|
}
|
|
25490
|
-
Logger_default.log(`[${usageId}] Waiting for ${workerThreads.length} worker(s) to complete`);
|
|
25491
|
-
executorResults.push(...await Promise.all(workerThreads));
|
|
25492
|
-
Logger_default.log(`[${usageId}] All ${workerThreads.length} worker(s) finished for producer "${prod.name}" file ${fileIndex + 1}/${totalFiles}`);
|
|
25493
25740
|
}
|
|
25494
25741
|
}
|
|
25495
|
-
await pool.terminate();
|
|
25496
25742
|
_progress.update({ phase: "Processing data", progress: 1 });
|
|
25497
25743
|
if (executorResults.some((x) => !Algo_default.hasVal(x)))
|
|
25498
25744
|
throw new Error(`${executorResults.filter((x) => !Algo_default.hasVal(x)).length} worker(s) failed to produce valid results`);
|
|
@@ -25507,7 +25753,7 @@ var ExecutorOrchestratorClass = class {
|
|
|
25507
25753
|
if (consumer.options?.distinct === true) {
|
|
25508
25754
|
Logger_default.log(`[${usageId}] Running unified distinct pass across merged workers`);
|
|
25509
25755
|
counter = performance.now();
|
|
25510
|
-
const unifiedOutputCount = await ConsumerExecutor_default.processDistinct(
|
|
25756
|
+
const unifiedOutputCount = await ConsumerExecutor_default.processDistinct(ExecutorScope_default.getMainPath(scope));
|
|
25511
25757
|
tracker.measure("process-distinct:main", performance.now() - counter);
|
|
25512
25758
|
postOperation.totalOutputCount = unifiedOutputCount;
|
|
25513
25759
|
Logger_default.log(`[${usageId}] Distinct pass complete: ${unifiedOutputCount} unique rows in ${Math.round(performance.now() - counter)}ms`);
|
|
@@ -25515,24 +25761,31 @@ var ExecutorOrchestratorClass = class {
|
|
|
25515
25761
|
if (consumer.options?.distinctOn) {
|
|
25516
25762
|
Logger_default.log(`[${usageId}] Running unified distinctOn pass (${consumer.options.distinctOn})`);
|
|
25517
25763
|
counter = performance.now();
|
|
25518
|
-
const unifiedOutputCount = await ConsumerExecutor_default.processDistinctOn(consumer,
|
|
25764
|
+
const unifiedOutputCount = await ConsumerExecutor_default.processDistinctOn(consumer, ExecutorScope_default.getMainPath(scope));
|
|
25519
25765
|
tracker.measure("process-distinct-on:main", performance.now() - counter);
|
|
25520
25766
|
postOperation.totalOutputCount = unifiedOutputCount;
|
|
25521
25767
|
Logger_default.log(`[${usageId}] DistinctOn pass complete: ${unifiedOutputCount} rows in ${Math.round(performance.now() - counter)}ms`);
|
|
25522
25768
|
}
|
|
25523
|
-
|
|
25524
|
-
|
|
25525
|
-
|
|
25526
|
-
|
|
25527
|
-
|
|
25528
|
-
|
|
25529
|
-
|
|
25530
|
-
|
|
25769
|
+
if (consumer.options?.pivot) {
|
|
25770
|
+
Logger_default.log(`[${usageId}] Running pivot operation`);
|
|
25771
|
+
counter = performance.now();
|
|
25772
|
+
const unifiedOutputCount = await ConsumerExecutor_default.processPivot(consumer, ExecutorScope_default.getMainPath(scope));
|
|
25773
|
+
tracker.measure("process-pivot:main", performance.now() - counter);
|
|
25774
|
+
postOperation.totalOutputCount = unifiedOutputCount;
|
|
25775
|
+
Logger_default.log(`[${usageId}] Pivot complete: ${unifiedOutputCount} rows in ${Math.round(performance.now() - counter)}ms`);
|
|
25776
|
+
}
|
|
25777
|
+
if (ConsumerManager_default.hasLineCountFields(consumer, true)) {
|
|
25778
|
+
Logger_default.log(`[${usageId}] Running unified lineCount pass across merged workers`);
|
|
25779
|
+
counter = performance.now();
|
|
25780
|
+
const processedLineCount = await ConsumerExecutor_default.processLineCount(consumer, ExecutorScope_default.getMainPath(scope), executorResults);
|
|
25781
|
+
tracker.measure("process-line-count:main", performance.now() - counter);
|
|
25782
|
+
Logger_default.log(`[${usageId}] LineCount pass complete: normalized ${processedLineCount} rows in ${Math.round(performance.now() - counter)}ms`);
|
|
25783
|
+
}
|
|
25531
25784
|
}
|
|
25532
25785
|
if (consumer.validate && consumer.validate.length > 0) {
|
|
25533
25786
|
Logger_default.log(`[${usageId}] Running dataset-level validations`);
|
|
25534
25787
|
counter = performance.now();
|
|
25535
|
-
const validationResults = await ConsumerExecutor_default.processDatasetValidation(consumer,
|
|
25788
|
+
const validationResults = await ConsumerExecutor_default.processDatasetValidation(consumer, ExecutorScope_default.getMainPath(scope));
|
|
25536
25789
|
tracker.measure("dataset-validation", performance.now() - counter);
|
|
25537
25790
|
for (const result of validationResults) {
|
|
25538
25791
|
if (result.onFail === "fail") {
|
|
@@ -25549,7 +25802,7 @@ var ExecutorOrchestratorClass = class {
|
|
|
25549
25802
|
Logger_default.log(`[${usageId}] Splitting output by size limit (${scope.limitFileSize})`);
|
|
25550
25803
|
counter = performance.now();
|
|
25551
25804
|
const writer = new ExecutorWriter_default();
|
|
25552
|
-
await writer.splitBySize(scope,
|
|
25805
|
+
await writer.splitBySize(scope, ExecutorScope_default.getMainPath(scope));
|
|
25553
25806
|
tracker.measure("split-by-size", performance.now() - counter);
|
|
25554
25807
|
Logger_default.log(`[${usageId}] Split complete in ${Math.round(performance.now() - counter)}ms`);
|
|
25555
25808
|
}
|
|
@@ -25557,7 +25810,7 @@ var ExecutorOrchestratorClass = class {
|
|
|
25557
25810
|
_progress.update({ phase: "Exporting result", progress: 0 });
|
|
25558
25811
|
counter = performance.now();
|
|
25559
25812
|
Logger_default.log(`[${usageId}] Exporting results to ${consumer.outputs.length} output(s)`);
|
|
25560
|
-
const exportRes = await OutputExecutor_default.exportResult(consumer,
|
|
25813
|
+
const exportRes = await OutputExecutor_default.exportResult(consumer, expandedFields, scope);
|
|
25561
25814
|
tracker.measure("export-result", performance.now() - counter);
|
|
25562
25815
|
Logger_default.log(`[${usageId}] Export complete in ${Math.round(performance.now() - counter)}ms (key: ${exportRes.key})`);
|
|
25563
25816
|
_progress.update({ phase: "Exporting result", progress: 1 });
|
|
@@ -25568,9 +25821,9 @@ var ExecutorOrchestratorClass = class {
|
|
|
25568
25821
|
tracker.measure("on-success-actions", performance.now() - counter);
|
|
25569
25822
|
Logger_default.log(`[${usageId}] On-success actions complete in ${Math.round(performance.now() - counter)}ms`);
|
|
25570
25823
|
}
|
|
25571
|
-
Logger_default.log(`[${usageId}] Starting cleanup operations`);
|
|
25824
|
+
Logger_default.log(`[${usageId}] Starting cleanup operations | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25572
25825
|
await this.performCleanupOperations(scope, tracker);
|
|
25573
|
-
const finalResult =
|
|
25826
|
+
const finalResult = OrchestratorHelper_default.computeFinalResult(tracker, executorResults, usageId, exportRes.key);
|
|
25574
25827
|
finalResult.elapsedMS = performance.now() - start;
|
|
25575
25828
|
if (Algo_default.hasVal(postOperation.totalOutputCount))
|
|
25576
25829
|
finalResult.outputCount = postOperation.totalOutputCount;
|
|
@@ -25579,9 +25832,10 @@ var ExecutorOrchestratorClass = class {
|
|
|
25579
25832
|
await Logger_default.flush();
|
|
25580
25833
|
return finalResult;
|
|
25581
25834
|
} catch (error) {
|
|
25582
|
-
Logger_default.log(`[${usageId}] Consumer "${consumer.name}" failed: ${Helper_default.asError(error).message}`);
|
|
25835
|
+
Logger_default.log(`[${usageId}] Consumer "${consumer.name}" failed: ${Helper_default.asError(error).message} | ${OrchestratorHelper_default.formatMemoryUsage()}`);
|
|
25583
25836
|
Logger_default.error(error);
|
|
25584
|
-
|
|
25837
|
+
if (activePool)
|
|
25838
|
+
await activePool.terminate();
|
|
25585
25839
|
await ConsumerOnFinishManager_default.onConsumerError(consumer, usageId);
|
|
25586
25840
|
Logger_default.log(`[${usageId}] Running cleanup after failure`);
|
|
25587
25841
|
await this.performCleanupOperations(scope, tracker);
|
|
@@ -25596,18 +25850,17 @@ var ExecutorOrchestratorClass = class {
|
|
|
25596
25850
|
* Returns a single chunk for small files where parallelism overhead isn't worth it.
|
|
25597
25851
|
*/
|
|
25598
25852
|
this.scopeWork = (fileUri, numChunks) => {
|
|
25599
|
-
const fileSize =
|
|
25853
|
+
const fileSize = import_fs13.default.statSync(fileUri).size;
|
|
25600
25854
|
if (fileSize === 0) return [];
|
|
25601
25855
|
if (fileSize < Constants_default.defaults.MIN_FILE_SIZE_FOR_PARALLEL) {
|
|
25602
25856
|
return [{ start: 0, end: fileSize, isFirstChunk: true, fileUri, index: 0 }];
|
|
25603
25857
|
}
|
|
25604
|
-
const
|
|
25605
|
-
const cpus = numChunks ?? Math.min(availableCores, Constants_default.defaults.MAX_THREAD_COUNT);
|
|
25858
|
+
const targetWorkers = numChunks ?? OrchestratorHelper_default.getParallelWorkerCount();
|
|
25606
25859
|
const maxChunksBySize = Math.floor(fileSize / Constants_default.defaults.MIN_CHUNK_SIZE);
|
|
25607
|
-
const effectiveChunks = Math.min(
|
|
25860
|
+
const effectiveChunks = Math.min(targetWorkers, maxChunksBySize);
|
|
25608
25861
|
if (effectiveChunks <= 1) return [{ start: 0, end: fileSize, isFirstChunk: true, fileUri, index: 0 }];
|
|
25609
25862
|
const targetChunkSize = Math.floor(fileSize / effectiveChunks);
|
|
25610
|
-
const fd =
|
|
25863
|
+
const fd = import_fs13.default.openSync(fileUri, "r");
|
|
25611
25864
|
try {
|
|
25612
25865
|
const offsets = [];
|
|
25613
25866
|
let currentStart = 0;
|
|
@@ -25625,7 +25878,23 @@ var ExecutorOrchestratorClass = class {
|
|
|
25625
25878
|
}
|
|
25626
25879
|
return offsets;
|
|
25627
25880
|
} finally {
|
|
25628
|
-
|
|
25881
|
+
import_fs13.default.closeSync(fd);
|
|
25882
|
+
}
|
|
25883
|
+
};
|
|
25884
|
+
this.assignChunkRowMetadata = (chunks, executorResults) => {
|
|
25885
|
+
const validResults = executorResults.filter((result) => Algo_default.hasVal(result));
|
|
25886
|
+
const resultsByChunkIndex = new Map(validResults.map((result) => [result.chunkIndex, result]));
|
|
25887
|
+
let nextRowOffset = 0;
|
|
25888
|
+
for (const chunk of chunks) {
|
|
25889
|
+
const result = resultsByChunkIndex.get(chunk.index);
|
|
25890
|
+
if (!result)
|
|
25891
|
+
continue;
|
|
25892
|
+
const rowCount = result.inputCount;
|
|
25893
|
+
chunk.rowOffset = nextRowOffset;
|
|
25894
|
+
chunk.rowCount = rowCount;
|
|
25895
|
+
result.rowOffset = nextRowOffset;
|
|
25896
|
+
result.rowCount = rowCount;
|
|
25897
|
+
nextRowOffset += rowCount;
|
|
25629
25898
|
}
|
|
25630
25899
|
};
|
|
25631
25900
|
/**
|
|
@@ -25638,7 +25907,7 @@ var ExecutorOrchestratorClass = class {
|
|
|
25638
25907
|
let currentPos = position;
|
|
25639
25908
|
while (currentPos < fileSize) {
|
|
25640
25909
|
const bytesToRead = Math.min(BUFFER_SIZE, fileSize - currentPos);
|
|
25641
|
-
const bytesRead =
|
|
25910
|
+
const bytesRead = import_fs13.default.readSync(fd, buffer, 0, bytesToRead, currentPos);
|
|
25642
25911
|
if (bytesRead === 0) break;
|
|
25643
25912
|
for (let i = 0; i < bytesRead; i++) {
|
|
25644
25913
|
if (buffer[i] === 10) {
|
|
@@ -25702,21 +25971,21 @@ var ExecutorOrchestratorClass = class {
|
|
|
25702
25971
|
startRow: prod.settings.startRow,
|
|
25703
25972
|
startColumn: prod.settings.startColumn
|
|
25704
25973
|
});
|
|
25705
|
-
await (0,
|
|
25974
|
+
await (0, import_promises10.pipeline)(
|
|
25706
25975
|
xlsCsvStream,
|
|
25707
|
-
|
|
25976
|
+
import_fs13.default.createWriteStream(decodedPath)
|
|
25708
25977
|
);
|
|
25709
|
-
const fileStats = await
|
|
25978
|
+
const fileStats = await import_promises9.default.stat(decodedPath);
|
|
25710
25979
|
decodedFiles.push({ fullUri: decodedPath, fileSize: fileStats.size });
|
|
25711
25980
|
decodedCount++;
|
|
25712
25981
|
continue;
|
|
25713
25982
|
}
|
|
25714
25983
|
if (inferredType === "XML") {
|
|
25715
|
-
const fileContent = await
|
|
25984
|
+
const fileContent = await import_promises9.default.readFile(file.fullUri, "utf-8");
|
|
25716
25985
|
const jsonData = XMLParser_default.xmlToJson(fileContent);
|
|
25717
25986
|
const records = normalizeXmlRows(jsonData);
|
|
25718
25987
|
if (records.length === 0) {
|
|
25719
|
-
await
|
|
25988
|
+
await import_promises9.default.writeFile(decodedPath, "", "utf-8");
|
|
25720
25989
|
} else {
|
|
25721
25990
|
const columns = [];
|
|
25722
25991
|
for (const record of records) {
|
|
@@ -25732,9 +26001,9 @@ var ExecutorOrchestratorClass = class {
|
|
|
25732
26001
|
const row = columns.map((column) => csvSafeValue(record[column]));
|
|
25733
26002
|
lines.push(CSVParser_default.stringifyRow(row));
|
|
25734
26003
|
}
|
|
25735
|
-
await
|
|
26004
|
+
await import_promises9.default.writeFile(decodedPath, lines.join("\n"), "utf-8");
|
|
25736
26005
|
}
|
|
25737
|
-
const fileStats = await
|
|
26006
|
+
const fileStats = await import_promises9.default.stat(decodedPath);
|
|
25738
26007
|
decodedFiles.push({ fullUri: decodedPath, fileSize: fileStats.size });
|
|
25739
26008
|
decodedCount++;
|
|
25740
26009
|
continue;
|
|
@@ -25753,86 +26022,32 @@ var ExecutorOrchestratorClass = class {
|
|
|
25753
26022
|
}));
|
|
25754
26023
|
return decodedResults;
|
|
25755
26024
|
};
|
|
25756
|
-
this._getWorkerPath = () => {
|
|
25757
|
-
const currentDir = __dirname;
|
|
25758
|
-
if (ProcessENVManager_default.getEnvVariable("NODE_ENV") === "dev" || ProcessENVManager_default.getEnvVariable("NODE_ENV") === "development")
|
|
25759
|
-
return import_path21.default.resolve("./.build/workers");
|
|
25760
|
-
const forcedPath = ProcessENVManager_default.getEnvVariable("REMORA_WORKERS_PATH");
|
|
25761
|
-
if (forcedPath && forcedPath.length > 0)
|
|
25762
|
-
return import_path21.default.join(__dirname, forcedPath);
|
|
25763
|
-
if (!currentDir.includes(".build")) {
|
|
25764
|
-
return import_path21.default.join(__dirname, "../workers");
|
|
25765
|
-
} else {
|
|
25766
|
-
return import_path21.default.resolve("./.build/workers");
|
|
25767
|
-
}
|
|
25768
|
-
};
|
|
25769
26025
|
this.reconcileExecutorThreadsResults = async (scope, executorResults, tracker) => {
|
|
25770
|
-
const mainPath =
|
|
26026
|
+
const mainPath = ExecutorScope_default.getMainPath(scope);
|
|
25771
26027
|
ConsumerExecutor_default._ensurePath(mainPath);
|
|
25772
26028
|
if (executorResults.length > 1) {
|
|
25773
26029
|
Logger_default.log(`[${scope.id}] Merging ${executorResults.length} worker output files into ${mainPath}`);
|
|
25774
26030
|
const perf = performance.now();
|
|
25775
26031
|
for (const workerResult of executorResults) {
|
|
25776
|
-
await (0,
|
|
25777
|
-
|
|
25778
|
-
|
|
26032
|
+
await (0, import_promises10.pipeline)(
|
|
26033
|
+
import_fs13.default.createReadStream(workerResult.resultUri),
|
|
26034
|
+
import_fs13.default.createWriteStream(mainPath, { flags: "a" })
|
|
25779
26035
|
);
|
|
25780
|
-
await
|
|
26036
|
+
await import_promises9.default.unlink(workerResult.resultUri);
|
|
25781
26037
|
}
|
|
25782
26038
|
tracker.measure("merge-workers", performance.now() - perf);
|
|
25783
26039
|
Logger_default.log(`[${scope.id}] Merge complete in ${Math.round(performance.now() - perf)}ms`);
|
|
25784
26040
|
} else if (executorResults.length === 1) {
|
|
25785
26041
|
Logger_default.log(`[${scope.id}] Single worker \u2014 renaming output to ${mainPath}`);
|
|
25786
|
-
await
|
|
26042
|
+
await import_promises9.default.rename(executorResults[0].resultUri, mainPath);
|
|
25787
26043
|
}
|
|
25788
26044
|
return mainPath;
|
|
25789
26045
|
};
|
|
25790
26046
|
this.performCleanupOperations = async (scope, tracker) => {
|
|
25791
26047
|
const start = performance.now();
|
|
25792
|
-
await
|
|
26048
|
+
await ExecutorScope_default.clearScope(scope);
|
|
25793
26049
|
tracker.measure("cleanup-operations", performance.now() - start);
|
|
25794
26050
|
};
|
|
25795
|
-
this.computeFinalResult = (tracker, executorResults, executionId, resultUri) => {
|
|
25796
|
-
const result = {
|
|
25797
|
-
cycles: Algo_default.max(executorResults.map((x) => x.cycles)),
|
|
25798
|
-
elapsedMS: Algo_default.sum(executorResults.map((x) => x.elapsedMS)),
|
|
25799
|
-
inputCount: Algo_default.sum(executorResults.map((x) => x.inputCount)),
|
|
25800
|
-
outputCount: Algo_default.sum(executorResults.map((x) => x.outputCount)),
|
|
25801
|
-
workerCount: executorResults.length,
|
|
25802
|
-
executionId,
|
|
25803
|
-
resultUri,
|
|
25804
|
-
operations: {}
|
|
25805
|
-
};
|
|
25806
|
-
for (const res of executorResults) {
|
|
25807
|
-
for (const opKey of Object.keys(res.operations)) {
|
|
25808
|
-
const op = res.operations[opKey];
|
|
25809
|
-
let label = result.operations[opKey];
|
|
25810
|
-
if (!label) {
|
|
25811
|
-
result.operations[opKey] = { avg: -1, max: -1, min: -1, elapsedMS: [] };
|
|
25812
|
-
label = result.operations[opKey];
|
|
25813
|
-
}
|
|
25814
|
-
label.elapsedMS.push(op.elapsedMS);
|
|
25815
|
-
}
|
|
25816
|
-
for (const opKey of Object.keys(result.operations)) {
|
|
25817
|
-
const operation = result.operations[opKey];
|
|
25818
|
-
if (operation.elapsedMS.length > 0) {
|
|
25819
|
-
operation.min = Math.min(...operation.elapsedMS);
|
|
25820
|
-
operation.max = Math.max(...operation.elapsedMS);
|
|
25821
|
-
operation.avg = Algo_default.mean(operation.elapsedMS);
|
|
25822
|
-
}
|
|
25823
|
-
}
|
|
25824
|
-
}
|
|
25825
|
-
const trackerOperations = tracker.getOperations();
|
|
25826
|
-
for (const opKey of Object.keys(trackerOperations)) {
|
|
25827
|
-
const trackerOp = trackerOperations[opKey];
|
|
25828
|
-
const value = trackerOp.elapsedMS;
|
|
25829
|
-
if (!result.operations[opKey]) {
|
|
25830
|
-
result.operations[opKey] = { avg: value, max: value, min: value, elapsedMS: [] };
|
|
25831
|
-
}
|
|
25832
|
-
result.operations[opKey].elapsedMS.push(value);
|
|
25833
|
-
}
|
|
25834
|
-
return result;
|
|
25835
|
-
};
|
|
25836
26051
|
this.onWorkAdvanced = (packet, workerId, progress, totalBytesToProcess, bytesProcessedByWorker) => {
|
|
25837
26052
|
const { processed } = packet;
|
|
25838
26053
|
bytesProcessedByWorker[workerId] = processed;
|
|
@@ -25972,21 +26187,21 @@ var discover = async (producerName) => {
|
|
|
25972
26187
|
|
|
25973
26188
|
// src/actions/create_producer.ts
|
|
25974
26189
|
var import_chalk8 = __toESM(require("chalk"));
|
|
25975
|
-
var
|
|
26190
|
+
var import_fs14 = __toESM(require("fs"));
|
|
25976
26191
|
var import_path22 = __toESM(require("path"));
|
|
25977
26192
|
var create_producer = async (name) => {
|
|
25978
26193
|
try {
|
|
25979
|
-
if (!
|
|
26194
|
+
if (!import_fs14.default.existsSync("./remora/producers")) {
|
|
25980
26195
|
throw new Error(import_chalk8.default.red("Missing directory: ") + import_chalk8.default.yellow("./remora/producers"));
|
|
25981
26196
|
}
|
|
25982
|
-
const defaultProducerTemplate =
|
|
26197
|
+
const defaultProducerTemplate = import_fs14.default.readFileSync(
|
|
25983
26198
|
import_path22.default.join(DOCUMENTATION_DIR, "default_resources/producer.json"),
|
|
25984
26199
|
"utf-8"
|
|
25985
26200
|
);
|
|
25986
26201
|
const defaultProducer = JSON.parse(defaultProducerTemplate);
|
|
25987
26202
|
defaultProducer.name = name;
|
|
25988
26203
|
const producerPath = import_path22.default.join("remora/producers", `${name}.json`);
|
|
25989
|
-
|
|
26204
|
+
import_fs14.default.writeFileSync(producerPath, JSON.stringify(defaultProducer, null, 4));
|
|
25990
26205
|
console.log(import_chalk8.default.green(`\u2705 Created producer config at ${producerPath}`));
|
|
25991
26206
|
console.log(import_chalk8.default.blue("Remember to:"));
|
|
25992
26207
|
console.log(import_chalk8.default.blue("1. Set the correct source name"));
|
|
@@ -26001,14 +26216,14 @@ var create_producer = async (name) => {
|
|
|
26001
26216
|
|
|
26002
26217
|
// src/actions/create_consumer.ts
|
|
26003
26218
|
var import_chalk9 = __toESM(require("chalk"));
|
|
26004
|
-
var
|
|
26219
|
+
var import_fs15 = __toESM(require("fs"));
|
|
26005
26220
|
var import_path23 = __toESM(require("path"));
|
|
26006
26221
|
var create_consumer = async (name, producerName) => {
|
|
26007
26222
|
try {
|
|
26008
|
-
if (!
|
|
26223
|
+
if (!import_fs15.default.existsSync("./remora/consumers")) {
|
|
26009
26224
|
throw new Error(import_chalk9.default.red("Missing directory: ") + import_chalk9.default.yellow("./remora/consumers"));
|
|
26010
26225
|
}
|
|
26011
|
-
const defaultConsumerTemplate =
|
|
26226
|
+
const defaultConsumerTemplate = import_fs15.default.readFileSync(
|
|
26012
26227
|
import_path23.default.join(DOCUMENTATION_DIR, "default_resources/consumer.json"),
|
|
26013
26228
|
"utf-8"
|
|
26014
26229
|
);
|
|
@@ -26016,10 +26231,10 @@ var create_consumer = async (name, producerName) => {
|
|
|
26016
26231
|
defaultConsumer.name = name;
|
|
26017
26232
|
if (producerName) {
|
|
26018
26233
|
const producerPath = import_path23.default.join("remora/producers", `${producerName}.json`);
|
|
26019
|
-
if (!
|
|
26234
|
+
if (!import_fs15.default.existsSync(producerPath)) {
|
|
26020
26235
|
throw new Error(import_chalk9.default.red("Producer not found: ") + import_chalk9.default.yellow(producerPath));
|
|
26021
26236
|
}
|
|
26022
|
-
const producerConfig = JSON.parse(
|
|
26237
|
+
const producerConfig = JSON.parse(import_fs15.default.readFileSync(producerPath, "utf-8"));
|
|
26023
26238
|
defaultConsumer.producers = [{ name: producerName }];
|
|
26024
26239
|
defaultConsumer.fields = producerConfig.dimensions.map((dim) => ({
|
|
26025
26240
|
key: dim.name,
|
|
@@ -26037,7 +26252,7 @@ var create_consumer = async (name, producerName) => {
|
|
|
26037
26252
|
defaultConsumer.metadata = void 0;
|
|
26038
26253
|
}
|
|
26039
26254
|
const consumerPath = import_path23.default.join("remora/consumers", `${name}.json`);
|
|
26040
|
-
|
|
26255
|
+
import_fs15.default.writeFileSync(consumerPath, JSON.stringify(defaultConsumer, null, 4));
|
|
26041
26256
|
console.log(import_chalk9.default.green(`\u2705 Created consumer config at ${consumerPath}`));
|
|
26042
26257
|
if (!producerName) {
|
|
26043
26258
|
console.log(import_chalk9.default.blue("Remember to:"));
|
|
@@ -26060,7 +26275,7 @@ var create_consumer = async (name, producerName) => {
|
|
|
26060
26275
|
// src/actions/automap.ts
|
|
26061
26276
|
var import_chalk10 = __toESM(require("chalk"));
|
|
26062
26277
|
var import_ora5 = __toESM(require("ora"));
|
|
26063
|
-
var
|
|
26278
|
+
var import_fs16 = __toESM(require("fs"));
|
|
26064
26279
|
var import_path24 = __toESM(require("path"));
|
|
26065
26280
|
var automap = async (producerName, schemaNames) => {
|
|
26066
26281
|
try {
|
|
@@ -26087,12 +26302,12 @@ var automap = async (producerName, schemaNames) => {
|
|
|
26087
26302
|
const mapResult = await AutoMapperEngine_default.map(sampleStrings, schemas, producer.settings.fileKey, [source]);
|
|
26088
26303
|
for (const producer2 of mapResult.producers) {
|
|
26089
26304
|
const producerPath = import_path24.default.join("remora/producers", `${producer2.name}.json`);
|
|
26090
|
-
|
|
26305
|
+
import_fs16.default.writeFileSync(producerPath, JSON.stringify(producer2, null, 4));
|
|
26091
26306
|
console.log(import_chalk10.default.blue(`Created producer: ${producer2.name}`));
|
|
26092
26307
|
}
|
|
26093
26308
|
for (const consumer of mapResult.consumers) {
|
|
26094
26309
|
const consumerPath = import_path24.default.join("remora/consumers", `${consumer.name}.json`);
|
|
26095
|
-
|
|
26310
|
+
import_fs16.default.writeFileSync(consumerPath, JSON.stringify(consumer, null, 4));
|
|
26096
26311
|
console.log(import_chalk10.default.blue(`Created consumer: ${consumer.name}`));
|
|
26097
26312
|
}
|
|
26098
26313
|
spinner.succeed("Producer has been successfully mapped");
|
|
@@ -26290,6 +26505,7 @@ if (!process.env.REMORA_RUNTIME_CONTEXT) {
|
|
|
26290
26505
|
process.env.REMORA_RUNTIME_CONTEXT = "cli";
|
|
26291
26506
|
Logger_default.warn('Missing property for REMORA_RUNTIME_CONTEXT during the Remora CLI startup. Defaulting to "cli" for this run. Set it manually in your environment.');
|
|
26292
26507
|
}
|
|
26508
|
+
ProcessShutdownManager_default.init("Remora CLI");
|
|
26293
26509
|
var program = new import_commander.Command();
|
|
26294
26510
|
var remoraLicenceKey = ProcessENVManager_default.getEnvVariable("REMORA_LICENCE_KEY");
|
|
26295
26511
|
var check = LicenceManager_default.validate(remoraLicenceKey);
|