I have the following code in my index.js file. This was my attempt to implement an external task worker for Camunda in node js after cloning this repo.
var Workers = require('camunda-worker-node');
var Backoff = require('camunda-worker-node/lib/backoff');
try {
console.log('In try ');
console.log(Backoff)
var engineEndPoint = process.env.ENGINE_URL || 'http://localhost:8080/engine-rest';
}
catch (e) {
console.log(e)
}
console.log("Out of try");
var uuid = require('uuid');
var workers = new Workers(engineEndPoint);
try {
Backoff(workers);
}
catch (e) {
console.log(e);
}
workers.subscribe('FightTribe', ['name'], function (context, callback) {
console.log("in worker subscribe");
if (Math.random() > 0.9) {
console.log('German Tribe Fighter, The Battle is lost.');
return callback(null, {
variables: {
legionStatus: "defeated"
}
});
}
console.log('German Tribe Fighter, The Battle is WON.');
callback(null, {
variables: {
legionStatus: 'Victorious'
}
})
});
My camunda process engine is up and running. On starting up index.js the process hangs at the function call Backoff(workers).
In an attempt to debug i placed console.log("in worker subscribe") in workers.subscribe, but the execution never reaches there.
I have attached my working directory. I am not sure what the issue is.
Related
What am I trying to do?
I want to clone multiple git repositories from nodejs.
How do I achieve that?
First I have this method in a separate file:
const exec = require("child_process").exec;
const { printError } = require("./printers");
function execute(command) {
console.log(`Running command: ${command}`);
let result = "";
let savedError = undefined;
return new Promise((resolve, reject) => {
const proc = exec(command, function (error, stdout, stderr) {
savedError = savedError || stderr || error;
result += stdout;
});
proc.on("close", (code) => {
if (code !== 0) {
console.error(
[
"================================================================",
`Command ${command} failed.`,
`Status code: ${code}`,
`Error message: ${savedError}`,
`Output: ${result}`,
"================================================================",
"",
].join("\n")
);
reject(result);
} else {
resolve(result);
}
});
});
Then I use it in my main module (code is abbreviated and bit simplified just so you can get the point:
const repoUrls = ["url1", "url2"]; // imagine these are real urls
async function main() {
const copyOfUrls = [...repoUrls];
while (copyOfUrls.length) {
try {
await execute(
`git clone ${copyOfUrls[0]} repositories/${repoUrlFileFriendly(
copyOfUrls[0]
)}`
);
console.log('fun fact - this console log never happens');
copyOfUrls.shift()
} catch (error) {
console.error("Failed to clone, see error:", error);
}
}
}
What is the problem?
Well, code works BUT after cloning first repo, the process exits (both the child process and the main one) and second repository is never even attempted to be cloned. (note the "console.log('fun fact - this console log never happens');").
I would like to know how to run code in my function 'myCustomMethod' via the Queue/Bull . Is this the right way to do it?
./models/Sport.js
export async function myCustomMethod(type, req)
{
console.log("This method should be executed via the Queue / Bull");
let computationResult = true;
return computationResult;
}
cronCustomFile.js
import { myCustomMethod } from './models/Sport.js';
cron.schedule('*/5 * * * * *', () =>
{
var battleRoyaleQueue = new Queue('battle_royale_queue');
console.log('Checking live events every 5 seconds');
battleRoyaleQueue.process(function (job, done)
{
try
{
console.log('Processing via battle_royale_queue');
myCustomMethod('live-events');
done();
}
catch (err)
{
console.log(err.message);
}
});
return true;
});
Bull version
"bull": "^3.6.0"
Additional information
It looks like jobs are not being added to the queue or processed.
Reference
https://github.com/OptimalBits/bull
In your code, you are creating a worker to process a job every 5 seconds, but you are not creating jobs to be processed. You should instead create the worker once, and then create a job that is added to a queue and processed repeatedly.
config/bull.js
import Queue from 'bull';
import { myCustomMethod } from '../models/Sport.js';
var battleRoyaleQueue = new Queue('battle_royale_queue');
battleRoyaleQueue.process(function(job, done) {
const { type } = job.data
try {
console.log('Processing via battle_royale_queue');
myCustomMethod(type);
done();
} catch (err) {
console.log(err.message);
}
});
recurringJob.js
import battleRoyaleQueue from '../config/queues.js';
const beginReccuringJob = (type) => {
battleRoyaleQueue.add({type: type}, { repeat: { cron: '*/5 * * * * *' } });
};
beginReccuringJob('live-events');
Have a node project deployed on heroku. Using the Heroku Scheduler some scheduling code seems to run but the Twilio SMS call does nothing. This code works outside of the scheduler.
This is the scheduler.js code that is run from Heroku Scheduler:
#!/usr/bin/env node
var config = require('../config');
var client = require('twilio')(config.accountSid, config.authToken);
function sayHello() {
console.log('Helloxxxx');
sendSms('+13476979750', 'from Scheduler');
console.log('goodbye-xxxx');
}
sayHello();
process.exit();
function sendSms(to, message) {
client.messages.create({
body: message,
to: to,
from: config.sendingNumber
}, function(err, data) {
if (err) {
console.error('Could not send message');
console.error(err);
} else {
console.error('SMS');
}
});
};
Twilio developer evangelist here.
I believe Yoni's answer is correct in that you are exiting the process before the HTTP request to the Twilio API completes. However, while promises are cool, I don't think you need all that extra code just to make this work. Instead you could just exit the process once you receive the callback.
Try this:
#!/usr/bin/env node
var config = require('../config');
var client = require('twilio')(config.accountSid, config.authToken);
function sayHello() {
console.log('Helloxxxx');
sendSms('+13476979750', 'from Scheduler');
console.log('goodbye-xxxx');
}
sayHello();
function sendSms(to, message) {
client.messages.create({
body: message,
to: to,
from: config.sendingNumber
}, function(err, data) {
if (err) {
console.error('Could not send message');
console.error(err);
} else {
console.error('SMS');
}
process.exit();
});
};
Seems to me you may be missing some async processing logic, so that your one-off dyno scheduled by Heroku scheduler is exiting (via process.exit()) before sayHello() has a chance to complete.
Try promisifying your code, with something like this (using the q library):
#!/usr/bin/env node
var config = require('../config');
var client = require('twilio')(config.accountSid, config.authToken);
var Q = require('q');
function sayHello() {
console.log('Helloxxxx');
return sendSms('+13476979750', 'from Scheduler')
.then(function(){
return console.log('goodbye-xxxx');
})
}
function sendSms(to, message) {
var deferred = Q.defer();
client.messages.create({
body: message,
to: to,
from: config.sendingNumber
}, function(err, data) {
if (err) {
console.error('Could not send message');
console.error(err);
deferred.reject(err);
} else {
console.log('SMS');
deferred.resolve();
}
});
return deferred.promise();
};
sayHello()
.then(function(){
console.log('Exiting...')
process.exit();
});
I am using Nodejs for the backend. I tried this npm package to create a simple work flow (AMAZON-SWF). The package has an example folder which contains files which I put in my node project so that I understand how it works.
The problem is that the Decider is not receiving any task from the SWF server. because of which my work flow never runs. Is there some configuration problem. Please point out what errors I have done.
Below is the code for quick reference. The only change the code has is the version number change and change in the domain name. Otherwise it is the same code as the code which you can find here.
Following is the decider code.
var swf = require('./index');
var myDecider = new swf.Decider({
"domain": "test-domain",
"taskList": {"name": "my-workflow-tasklist"},
"identity": "Decider-01",
"maximumPageSize": 100,
"reverseOrder": false // IMPORTANT: must replay events in the right order, ie. from the start
});
myDecider.on('decisionTask', function (decisionTask) {
console.log("Got a new decision task !");
if(!decisionTask.eventList.scheduled('step1')) {
decisionTask.response.schedule({
name: 'step1',
activity: 'simple-activity'
});
}
else {
decisionTask.response.stop({
result: "some workflow output data"
});
}
decisionTask.response.respondCompleted(decisionTask.response.decisions, function(err, result) {
if(err) {
console.log(err);
return;
}
console.log("responded with some data !");
});
});
myDecider.on('poll', function(d) {
//console.log(_this.config.identity + ": polling for decision tasks...");
console.log("polling for tasks...", d);
});
// Start polling
myDecider.start();
/**
* It is not recommanded to stop the poller in the middle of a long-polling request,
* because SWF might schedule an DecisionTask to this poller anyway, which will obviously timeout.
*
* The .stop() method will wait for the end of the current polling request,
* eventually wait for a last decision execution, then stop properly :
*/
process.on('SIGINT', function () {
console.log('Got SIGINT ! Stopping decider poller after this request...please wait...');
myDecider.stop();
});
Following is activity code:
/**
* This simple worker example will respond to any incoming task
* on the 'my-workflow-tasklist, by setting the input parameters as the results of the task
*/
var swf = require('./index');
var activityPoller = new swf.ActivityPoller({
domain: 'test-domain-newspecies',
taskList: { name: 'my-workflow-tasklist' },
identity: 'simple-activity'
});
activityPoller.on('error',function() {
console.log('error');
});
activityPoller.on('activityTask', function(task) {
console.log("Received new activity task !");
var output = task.input;
task.respondCompleted(output, function (err) {
if(err) {
console.log(err);
return;
}
console.log("responded with some data !");
});
});
activityPoller.on('poll', function(d) {
console.log("polling for activity tasks...", d);
});
activityPoller.on('error', function(error) {
console.log(error);
});
// Start polling
activityPoller.start();
/**
* It is not recommanded to stop the poller in the middle of a long-polling request,
* because SWF might schedule an ActivityTask to this poller anyway, which will obviously timeout.
*
* The .stop() method will wait for the end of the current polling request,
* eventually wait for a last activity execution, then stop properly :
*/
process.on('SIGINT', function () {
console.log('Got SIGINT ! Stopping activity poller after this request...please wait...');
activityPoller.stop();
});
Following is the code which registers:
var awsswf = require('./index');
var swf = awsswf.createClient();
/**
* Register the domain "test-domain"
*/
swf.registerDomain({
name: "test-domain-newspecies",
description: "this is a just a test domain",
workflowExecutionRetentionPeriodInDays: "3"
}, function (err, results) {
if (err && err.code != 'DomainAlreadyExistsFault') {
console.log("Unable to register domain: ", err);
return;
}
console.log("'test-domain-newspecies' registered !")
/**
* Register the WorkflowType "simple-workflow"
*/
swf.registerWorkflowType({
domain: "test-domain-newspecies",
name: "simple-workflow",
version: "2.0"
}, function (err, results) {
if (err && err.code != 'TypeAlreadyExistsFault') {
console.log("Unable to register workflow: ", err);
return;
}
console.log("'simple-workflow' registered !")
/**
* Register the ActivityType "simple-activity"
*/
swf.registerActivityType({
domain: "test-domain-newspecies",
name: "simple-activity",
version: "2.0"
}, function (err, results) {
if (err && err.code != 'TypeAlreadyExistsFault') {
console.log("Unable to register activity type: ", err);
return;
}
console.log("'simple-activity' registered !");
});
});
});
Following is the code which starts the workflow execution:
var swf = require('./index');
var workflow = new swf.Workflow({
"domain": "test-domain-newspecies",
"workflowType": {
"name": "simple-workflow",
"version": "2.0"
},
"taskList": { "name": "my-workflow-tasklist" },
"executionStartToCloseTimeout": "1800",
"taskStartToCloseTimeout": "1800",
"tagList": ["example"],
"childPolicy": "TERMINATE"
});
var workflowExecution = workflow.start({ input: "any data ..."}, function (err, runId) {
if (err) { console.log("Cannot start workflow : ", err); return; }
console.log("Workflow started, runId: " +runId);
});
Following is index.js file
var basePath = "../node_modules/aws-swf/lib/";
exports.AWS = require('aws-swf').AWS;
exports.AWS.config.loadFromPath(__dirname + '/../config/awsConfig.json');
exports.createClient = require(basePath+"swf").createClient;
exports.Workflow = require(basePath+"workflow").Workflow;
exports.WorkflowExecution = require(basePath+"workflow-execution").WorkflowExecution;
exports.ActivityPoller = require(basePath+"activity-poller").ActivityPoller;
exports.ActivityTask = require(basePath+"activity-task").ActivityTask;
exports.Decider = require(basePath+"decider").Decider;
exports.DecisionTask = require(basePath+"decision-task").DecisionTask;
exports.EventList = require(basePath+"event-list").EventList;
exports.DecisionResponse = require(basePath+"decision-response").DecisionResponse;
exports.Poller = require(basePath+"poller").Poller;
The way run this code is by opening three terminal simultaneously. Then I execute the following command in respective terminal.
activity
node <activity-file-name>
decider
node <decider-file-name>
start and register I run in the same terminal.
node <register-file-name>
node <start-file-name>
It stands out that in the decider you are using "test-domain", but in the rest of the code you are using"test-domain-newspecies".
If the domain "test-domain" is not registered you should get an UnknownResourceFault error when polling for a decision task.
I am working on a node app that essentially is a simple AWS SQS poller that should sit and listen to new items in different queues.
Here is my module.export:
module.exports = {
readMessage: function(qParams, qType, tableName) {
logger.debug(qType);
SQS.receiveMessage(qParams, handleSqsResponse);
function handleSqsResponse (err, data) {
if(err) logger.error("handleSqsResponse error:" + err);
if (data && data.Messages) {
data.Messages.forEach(processMessage)
readMessage(); // continue reading until draining the queue (or UPTIME reached)
}
else{
logger.debug("no data in sqs.");
// process.exit();
}
}
// 'processing' is mainly writing to logs using winston. Could add here any transformations and transmission to remote systems
function processMessage(sqsMessage){
// Parse sqs messag
var msgObj = JSON.parse(sqsMessage.Body);
// Process
logger.info(msgObj.Message);
_.extend(qParams, { "ReceiptHandle": sqsMessage.ReceiptHandle });
dbMap[qType](msgObj, qParams, tableName);
}
}
}
The issue I am running into is when I attempt to call readMessage(); again. I get the error of ReferenceError: readMessage is not defined
module.exports is a plain object that is exposed to outer modules that has a method readMessage. readMessage() should be module.exports.readMessage().
Also i would suggest creating a variable and then exporting that:
var obj = {
readMessage: function(qParams, qType, tableName) {
logger.debug(qType);
SQS.receiveMessage(qParams, handleSqsResponse);
function handleSqsResponse (err, data) {
if(err) logger.error("handleSqsResponse error:" + err);
if (data && data.Messages) {
data.Messages.forEach(processMessage)
obj.readMessage(); // continue reading until draining the queue (or UPTIME reached)
}
else{
logger.debug("no data in sqs.");
// process.exit();
}
}
// 'processing' is mainly writing to logs using winston. Could add here any transformations and transmission to remote systems
function processMessage(sqsMessage){
// Parse sqs messag
var msgObj = JSON.parse(sqsMessage.Body);
// Process
logger.info(msgObj.Message);
_.extend(qParams, { "ReceiptHandle": sqsMessage.ReceiptHandle });
dbMap[qType](msgObj, qParams, tableName);
}
}
}
module.exports = obj;
Please note that I only responded to the question you specifically asked. I didn't take into account any architectural issue associate with the code.
function functionName(has = false){
var total = 0;
if(has){
functionName(true)
} else {
// Todo
}
}
module.exports.functionName = functionName;