@metacall/faas
Version:
Reimplementation of MetaCall FaaS platform written in TypeScript.
131 lines (130 loc) • 4.9 kB
JavaScript
;
/* eslint-disable */
Object.defineProperty(exports, "__esModule", { value: true });
const package_1 = require("@metacall/protocol/package");
const fs_1 = require("fs");
const metacall_1 = require("metacall");
const os_1 = require("os");
const path_1 = require("path");
const protocol_1 = require("./protocol");
const functions = {};
const createMetacallJsonFiles = async (path, jsons) => {
for (const el of jsons) {
const filePath = path_1.join(path, `metacall-${el.language_id}.json`);
await fs_1.promises.writeFile(filePath, JSON.stringify(el));
}
};
const loadDeployment = (resource, jsonPaths) => {
const deployment = {
status: 'create',
prefix: os_1.hostname(),
suffix: resource.id,
version: 'v1',
packages: {},
ports: []
};
const configurations = jsonPaths.map(path => {
const jsonPath = path_1.join(resource.path, path);
return {
path: jsonPath,
json: require(jsonPath)
};
});
const languages = new Set(configurations.map(({ json }) => json.language_id));
// Load resource path for each language
for (const tag of languages) {
metacall_1.metacall_execution_path(tag, resource.path);
}
for (const { path, json } of configurations) {
if (!json.language_id) {
throw new Error(`Field language_id not found in ${path}`);
}
// Load execution path for each json
const executionPath = path_1.join(resource.path, json.path);
metacall_1.metacall_execution_path(json.language_id, executionPath);
// Load the json into metacall
const exports = metacall_1.metacall_load_from_configuration_export(path);
// Get the inspect information
const inspect = metacall_1.metacall_inspect();
deployment.packages[json.language_id] =
inspect[json.language_id];
// Store the functions
Object.keys(exports).forEach(func => {
functions[func] = exports[func];
});
}
return deployment;
};
const handleDeployment = async (resource) => {
// Check if the deploy comes with extra JSONs and store them
if (resource.jsons.length > 0) {
const jsonPaths = await createMetacallJsonFiles(resource.path, resource.jsons);
}
// List all files except by the ignored ones
const filesPaths = await package_1.findFilesPath(resource.path);
// Get the JSONs from the list of files
const jsonPaths = package_1.findMetaCallJsons(filesPaths);
// Deploy the JSONs
const deployment = loadDeployment(resource, jsonPaths);
// Mark as ready so CLI and tests see deployment as fully up
deployment.status = 'ready';
return deployment;
};
process.on('message', (payload) => {
switch (payload.type) {
// Handle deploy load
case protocol_1.WorkerMessageType.Load: {
const resource = payload.data;
handleDeployment(resource)
.then(app => {
if (process.send) {
process.send({
type: protocol_1.WorkerMessageType.MetaData,
data: app
});
}
})
.catch(err => {
console.log(err);
process.exit(1);
});
break;
}
// Handle invoke function
case protocol_1.WorkerMessageType.Invoke: {
const fn = payload.data;
void (async () => {
try {
const result = await functions[fn.name](...fn.args);
if (process.send) {
process.send({
type: protocol_1.WorkerMessageType.InvokeResult,
data: {
id: fn.id,
result: result
}
});
}
}
catch (err) {
// We must inform the master about the error or handle it gracefully.
// Since there wasn't an explicit InvokeError type, we'll mimic the old
// behavior but at least prevent the worker from crashing silently.
console.error(`Error executing function ${fn.name}:`, err);
if (process.send) {
process.send({
type: protocol_1.WorkerMessageType.InvokeResult,
data: {
id: fn.id,
result: { error: String(err) }
}
});
}
}
})();
break;
}
default:
break;
}
});