Packages

Package Elixir for Lambda and run via shim

Current section

Files

Jump to
lambda_shim priv templates index.js.eex
Raw

priv/templates/index.js.eex

'use strict';
const app = '<%= app %>';
const erts_version = "9.0";
const PORT = '<%= http_shim_port %>';
const MAX_FAILS = 1;
const fs = require("fs")
const version = "0.1.0";
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const spawn = require('child_process').spawn;
const http = require("http");
const EPMD_STARTED_INDICATOR = 'epmd running - daemon = 0';
const APPLICATION_STARTED_INDINCATOR = 'SHIM_APPLICATION_STARTED';
const epmdStarted = defer();
const applicationStarted = defer();
function restart(message) {
console.error('Critical error detected, attempted to force restart of container:');
console.error(message || 'Unknown reason');
process.exit(1);
}
function log() {
console.log.apply(console, ['NODE_ELIXIR_SHIM'].concat(Array.prototype.slice.call(arguments)));
}
epmdStarted.promise.then(function () {
log('EPMD_STARTED');
});
applicationStarted.promise.then(function () {
log('APPLICATION_STARTED');
});
if (process.env.NODE_ENV !== 'test') {
execSync('cp -r /var/task/burn/ /tmp/');
}
function setupEnv(target) {
target["HOME"] = "/var/task/burn"
target["ERL_EPMD_ADDRESS"] = "127.0.0.1";
target["LANG"] = "en_US.utf-8";
target["LC_ALL"] = "en_US.utf-8";
target["PORT"] = PORT
return target;
}
log('Spawning epmd');
const epmd = spawn('/tmp/burn/erts-9.0/bin/epmd', ['-d', '-relaxed_command_check', '-port', 40006], { detached: true });
epmd.stdout.on('data', function (data) {
log("epmd stdout", data.toString());
if (data.toString().indexOf(EPMD_STARTED_INDICATOR) > -1) {
epmdStarted.resolve();
}
});
epmd.stderr.on('data', function (data) {
log("epmd stderr", data.toString());
if (data.toString().indexOf(EPMD_STARTED_INDICATOR) > -1) {
epmdStarted.resolve();
}
});
epmd.on('error', function (err) {
log("epmd error", err.toString());
epmdStarted.reject(err);
});
epmd.on('exit', function (code) {
log("epmd exit", code);
epmdStarted.reject(new Error(`epmd exited with code ${code}`));
});
epmd.unref();
execSync('sleep 1');
log('Spawning elixir_proc');
const elixir_proc = spawn('/tmp/burn/bin/'+app, ['foreground'], {
detached: true,
env: setupEnv(process.env)
});
elixir_proc.stdout.on('data', function (data) {
log('elixir_proc stdout', data.toString());
if (data.toString().indexOf(APPLICATION_STARTED_INDINCATOR) > -1) {
applicationStarted.resolve();
}
});
elixir_proc.stderr.on('data', function (data) {
data = data.toString();
log('elixir_proc stderr', data);
if (data.indexOf('Fatal error') > -1) return restart('Fatal error in elixir process');
});
elixir_proc.on('error', function(err) {
log('elixir_proc error', err.stack);
applicationStarted.reject(err);
});
elixir_proc.on('exit', function(code) {
log('elixir_proc exited', code);
applicationStarted.reject(new Error(`elixir_proc exited with code ${code}`));
});
execSync('sleep 2');
exports.handler = function(event, context, callback) {
context.callbackWaitsForEmptyEventLoop = false;
applicationStarted.promise.then(function () {
const body = JSON.stringify(event);
log('Proxying request to elixir http server');
const request = http.request({
hostname: 'localhost',
port: PORT,
path: '/',
method: 'POST',
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body)
}
}, function (response) {
const statusCode = response.statusCode;
const contentType = response.headers['content-type'];
const buffers = [];
response.on('data', function (chunk) {
buffers.push(chunk);
});
response.on('end', () => {
try {
let responseBody = Buffer.concat(buffers).toString('utf8');
if (statusCode !== 200) {
return callback(new Error(`Request Failed.\n Status Code: ${statusCode}\n Body: ${responseBody}`));
}
if (contentType.indexOf('application/json') > -1) responseBody = JSON.parse(responseBody);
log('Proxy response', responseBody);
return callback(null, responseBody);
} catch (err) {
console.error(err.stack);
callback(err);
}
});
});
request.on('error', (err) => {
console.error(err.stack);
callback(err);
restart('Elixir http shim unreachable ' + err.message);
});
request.end(body);
}).catch(callback);
}
function defer() {
var resolve, reject;
var promise = new Promise(function() {
resolve = arguments[0];
reject = arguments[1];
});
return {
resolve: resolve,
reject: reject,
promise: promise
};
}