Since the JavaScript main thread runs infinitely until all callstack goes empty, I am using setTimeout to create a session on demand and instead of sending expiration time, I am using setTimeout to pop the session after every N minutes.
Now I am deploying my backend in Node using serverless cloud functions (In Vercel, to be more specific). I wanted to know if it is advisable to use setTimeout since it will keep re-running main thread until the timeout completes and the callback executes in a serverless function or should I completely discard this approach?
Here's how my implementation looks like:
const ttl = 3600 * 1000;
const addSession = async (ua: string): Promise<string> => {
const snapshot = await ref.push({ ua });
setTimeout(() => {
if (snapshot.key) ref.child(snapshot.key).remove();
}, ttl);
if (!snapshot.key) return addSession(ua);
return snapshot.key;
}
Related
I'm trying to do something that involves a global context that knows about what function is running at the moment.
This is easy with single-threaded synchronous functions, they start off running and finish running when they return.
But async functions can pop to the bottom of the program and climb back up multiple times before completing.
let currentlyRunningStack: string[] = [];
function run(id: string, cb: () => any) {
currentlyRunningStack.push(id);
cb()
currentlyRunningStack.shift();
}
// works with synchronous stuff
run("foo", () => {
run("bar", () => console.log("bar should be running"));
console.log("now foo is running");
});
// can it work with asynchronous
run("qux", async () => {
// async functions never run immediately...
await somePromise();
// and they start and stop a lot
});
Is it possible to keep track of whether or not an asynchronous function is currently running or currently waiting on something?
EDIT: there appears to be something similar called Zone.js. Used by Angular I guess.
Something like async_hooks for the browser?
EDIT: per #Bergi's suggestion, the word "stack" has been updated to "program" for clarification
It is possible, and someone has done it -- the angular developers, no less -- but it costs a whopping 5.41Mb!!
https://www.npmjs.com/package/zone.js
This was ripped from this very similar question: Something like async_hooks for the browser?
In order to distinguish from that question a bit, I'll answer the core query here:
Yes, you can tell when an async function stops and starts. You can see a lot of what's required in the project code
In particular, this file appears to handle poly-filling promises, though I'd need more time to verify this is where the magic happens. Perhaps with some effort I can distill this into something simpler to understand, that doesn't require 5.41 Mb to acheive.
Yes, it possible.
Using a running context, like a mutex, provided by Edgar W. Djiskistra, stack queues, Promise states and Promise.all executor. This way you can keep track if there's a running function in the program. You will have to implement a garbage collector, keeping the mutex list clean and will need a timer(setTimeout) to verify if the context is clean. When the context is clean, you will call a callback-like function to end you program, like process.exit(0). By context we refeer to the entire program order of execution.
Transforming the function into a promise with an .then callback to pop/clean the stack of the mutex after the execution of content of the function with a try/catch block to throw, handle, or log errors add more control to the hole program.
The introduction of setTimeout propicies a state machine, combined with the mutex/lock and introduces a memory leak that you will need to keep track of the timer to clear the memory allocated by each function.
This is done by neste try/catch. The use of setInterval for it introduces a memory leak that will cause a buffer overflow.
The timer will do the end of the program and there's it. You can keep track if a function is running or not and have every function registered running in a syncrhonous manner using await with and mutex.
Running the program/interpreter in a syncrhonous way avoid the memory leaks and race conditions, and work well. Some code example below.
const async run (fn) => {
const functionContextExecutionStackLength = functionExecutionStackLength + 1
const checkMutexStackQueue = () => {
if (mutexStack[0] instanceof Promise) {
if (mutex[0].state == "fullfiled") {
mutexStack = mutexStack.split(1, mutexStack.length)
runner.clear()
runner()
}
}
if (mutexStack.length == 0) process.exit(0)
}
// clear function Exection Context
const stackCleaner = setTimeout(1000, (err, callback) => {
if (functionContextExecutionStackLength == 10) {
runner.clear()
}
})
stackCleaner = stackCleaner()
// avoid memory leak on function execution context
if (functionContextExecutionStackLength == 10) {
stackCleaner.clear()
stackCleaner()
}
// the runner
const runner = setTimeout(1, async (err, callback) => {
// run syncronous
const append = (fn) => mutex.append(util.promisfy(fn)
.then(appendFunctionExectionContextTimes)
.then(checkMutexStackQueue))
// tranaform into promise with callback
const fn1 = () => util.promify(fn)
const fn2 = () => util.promisfy(append)
const orderOfExecution = [fn1, fn2, fn]
// a for await version can be considered
for (let i = 0; i < orderOfExecution.length; i++) {
if (orderOfExecution.length == index) {
orderOfExecution[orderOfExecution.length]()
} else {
try {
orderOfExecution[i]()
} catch (err) {
throw err
console.error(err)
}
}
}
}
}
(() => run())(fn)
On the code above we take the assynchronous caracterisc of javascript very seriously. Avoiding it when necessary and using it when is needed.
Obs:
Some variables was ommited but this is a demo code.
Sometimes you will see a variables context switching and call before execution, this is due to the es modules characteriscts of reading it all and interpreting it later.
I am looking to set a delay in making http requests to avoid going over the rate limit of the external server.
users.forEach(async function(user) {
await rate_check()
make_http_request()
})
I need help with implementing the rate_check function in a way that would avoid busy waiting. At the moment, I am busy waiting as follows
async function rate_check() {
if(rate_counter < rate_limit)
rate_counter += 1
else {
// Busy wait
while(new Date() - rate_0_time < 1000) {}
rate_counter = 1
time_delta = new Date() - rate_0_time
rate_1_time = new Date()
}
}
await new Promise(resolve => { setTimeout(resolve, 2000)}) does not work as it would only cause rate_check to sleep, but the anonymous function would continue to make requests.
Any rate checking code must be done in the rate_check function and not in the function where the http request happens as requests happen across multiple async functions and they are making requests to the same server.
I am open to any other suggestions as well as refactoring as long as it avoids nesting callbacks or third-party dependency
You can use the lodash throttle function https://lodash.com/docs/4.17.15#throttle to wrap around your side effect function. It will at most call it once per interval and memoize the last returned result (so you may want to return data instead of a stateful object such as an http body).
Using nodejs 8.12 on Gnu/Linux CentOS 7. Using the built-in web server, require('https'), for a simple application.
I understand that nodejs is single threaded (single process) and there is no actual parallel execution of code. Based on my understanding, I think the http/https server will process one http request and run the handler through all synchronous statements and set up asynchronous statements to be executed later before it will return to process a subsequent request. However, with http/https libraries, you have an asynchronous code that is used to assemble the body of the request. So, we already have one callback which is executed when the body is ready ('end' event). This fact makes me think it might be possible to be in the middle of processing two or more requests simultaneously.
As part of handling the requests, I need to execute a string of shell commands and I use the shelljs.exec library to do that. It runs synchronously, waiting until complete before returning. So, example code would look like:
const shelljs_exec = require('shelljs.exec');
function process() {
// bunch of shell commands in string
var command_str = 'command1; command2; command3';
var exec_results = shelljs_exec(command_str);
console.log('just executed shelljs_exec command');
var proc_results = process_results(exec_results);
console.log(proc_results);
// and return the response...
}
So node.js runs the shelljs_exec() and waits for completion. While it's waiting, can another request be worked on, such that there is a risk, slight, of two or more shelljs.exec invocations running at the same time? Since that could be a problem, I need to ensure only one shelljs.exec statement can be in progress at a given time.
If that is not a correct understanding, then I was thinking I need to do something with mutex locks. Like this:
const shelljs_exec = require('shelljs.exec');
const locks = require('locks');
// Need this in global scope - so we are all dealing with the same one.
var mutex = locks.createMutex();
function await_lock(shell_commands) {
var commands = shell_commands;
return new Promise(getting_lock => {
mutex.lock(got_lock_and_execute);
});
function got_lock_and_execute() {
var exec_results = shelljs_exec(commands);
console.log('just executed shelljs_exec command');
mutex.unlock();
return exec_results;
}
}
async function process() {
// bunch of shell commands in string
var command_str = 'command1; command2; command3';
exec_results = await await_lock(command_str);
var proc_results = process_results(exec_results);
console.log(proc_results);
}
If shelljs_exec is synchronous, no need.
If it is not. If it takes a callback wrap it in a Promise constructor so that it can be awaited. I would suggest properly wrapping the mutex.lock in a promise that gets resolved when the lock is acquired. The try finally is needed to ensure that the mutex is unlocked if shelljs_exec throws an exception.
async function await_lock(shell_commands) {
await (new Promise(function(resolve, reject) {
mutex.lock(resolve);
}));
try {
let exec_results = await shelljs_exec(commands);
return exec_results;
} finally {
mutex.unlock();
}
}
Untested. But it looks like it should work.
I was wondering if someone could help me with this issue that I have...
Our client has an Legacy API which retrieves messages from users, and they want us to implement a polling mechanism for it that, based on an specific interval, updates the information within the page. Period.
They want to have a reliable polling strategy so (as you may already know) I'm using setTimeout to pull that off.
TL;DR: Does anyone one of you knows how to pull out an efficient polling utility that doesn't leak memory?
I'm trying to pull off an utility that allows me to add certain actions to a "polling list" and run the "polling" right there.
For example, I have an "actions list" similar to this:
const actions = new Map();
actions.set('1', ('1', {
action: () => {
console.log('action being executed...');
return 'a value';
},
onFinished: (...param) => { console.log(param); },
name: 'name of the action',
id: '1'
}));
I'm using Map for both api convenience and lookup performance and I'm adding a fake action to it (some of the params might not be needed but they're there for testing purposes).
Regarding the polling, I've created a delay fn to handle the timeout as a Promise (just for readability sake. It shouldn't affect the call stack usage whatsoever):
function delay(timeout) {
return new Promise(function delay(resolve) {
setTimeout(resolve, timeout);
});
}
And the polling fn that I came up with looks like this:
async function do_stuff(id, interval) {
const action = actions.get(id);
// breakout condition
if (action.status === 'stop') {
return;
}
console.log('processing...');
const response = await action.action();
console.log('executing action onFinished...');
action.onFinished(action.name, response);
delay(interval).then(function callAgain() {
do_stuff(id, interval);
});
}
I've used async/await in here because my action.action() will be mostly async operations and I'm using .then after the delay because I want to use the browser's EventTable to handle my resolve functions instead of the browser's stack. Also, I'm using named functions for debugging purposes.
To run the polling function, I just do:
const actionId = '1';
const interval = 1000;
do_stuff(actionId, interval);
And to stop the poll of that particular action, I run:
actions.get(actionId).status = 'stop'; // not fancy but effective
So far so good.... not! This surely has a ton of issues, but the one that bothers me the most of the JS Heap usage.
I ran a couple of tests using the Performance Tab from Chrome DevTools (Chrome version 64) and this is what I got:
Using an interval of 10 milliseconds
- 1000ms: polling started
- 10000ms: polling stopped
- 13000ms: ran a manual GC
Using an interval of 1 second
1000ms: polling started
10000ms: polling stopped
13000ms: ran a manual GC
Does anyone know why is this behaving like this? Why the GC it's running more frequently when I decrease the interval? Is it a memory leak or a stack issue? Are there any tools I could use to keep investigating about this issue?
Thanks in advance!
Stuff that I've read:
http://reallifejs.com/brainchunks/repeated-events-timeout-or-interval/ (why choosing setTimeout instead of setInterval)
Building a promise chain recursively in javascript - memory considerations
How do I stop memory leaks with recursive javascript promises?
How to break out of AJAX polling done using setTimeout
https://alexn.org/blog/2017/10/11/javascript-promise-leaks-memory.html
PS: I've putted the snippet right here in case anyone wants to give it a try.
const actions = new Map();
actions.set('1', ('1', {
action: () => {
console.log('action being executed...');
return 'a value';
},
onFinished: (...param) => { console.log(param); },
name: 'name of the action',
id: '1'
}));
function delay(timeout) {
return new Promise(function delay(resolve) {
setTimeout(resolve, timeout);
});
}
async function do_stuff(id, interval) {
const action = actions.get(id);
// breakout condition
if (action.status === 'stop') {
return;
}
console.log('processing...');
const response = await action.action();
console.log('executing action onFinished...');
action.onFinished(action.name, response);
delay(interval).then(function callAgain() {
do_stuff(id, interval);
});
}
/*
// one way to run it:
do_stuff('1', 1000);
// to stop it
actions.get('1').status = 'stop';
*/
There is something I want to code in nodejs, but I don't have any idea of how to implement it. I've been reading and searching a lot, and still have not idea of what would be the correct way to do it.
The problem is the following:
Read lines from stdin
For each line, launch an http request
There must be a limit to simultaneous http
Write the line readed plus some data obtained from the http request to stdout
Lines must be written in order
You can not read "all" the file and then split lines: you must process one line at a time, remember it's stdin. You don't know when the input will end.
Does anybody have some clues of how to approach this problem? I do not have any idea of how to proceed.
You could do something like this:
const http = require('http');
const Promise = require('bluebird');
let arrayOfRequests = [];
process.stdin.on('data', (data) => {
//get data from the stdin
//then add the request to the array
arrayOfRequests.push(http.get({}))
})
process.stdin.on('end', () => {
Promise.all(arrayOfRequests)
// use Promise .all to bundle all of the reuqest
//then use the spread operator so you can use all of the reuqest In order
.spread( (request1,request2,request3) => {
// do stuff
})
})
FYI, the snippet wont work.
So what you are doing is using the process.stdin that is built into Node.js. Then you are bundling all of the requests. Whenever the user cancels out of the program, your requests will be made. Since the calls will be async, you have them in an array, then run Promsise.all and use the bluebird .spread operator to deconstruct the Promise.all and get the values.
So far, I've got this solution for the producer-consumer problem in nodejs, where the producer don't produce more data until there is space available in the queue.
This is queue's code, based on block-queue: https://gist.github.com/AlvaroMaceda/8a933a317fed3fd4691fd5eda3e60c5e
To use the blocking queue, you create it with 3 parameters:
Number of tasks running concurrently
"Push" function. It will be called with the queue as parameter when
more data is needed. The task will be added with an identifier.
"Task" function. It will be called with the identifier created by
"Push" function.
The queue will call "push" only when more data is needed. For example, if there are five tasks running and it was created with a maximum of 5 concurrent tasks, "push" won't be called until one of these tasks end.
This is an example of how to use it:
"use strict";
const queue = require('./block-queue');
const CONCURRENCY = 5;
const WORKS_TO_LAUNCH = 10;
const TIMEOUT = 200;
let i = 1;
let q = queue(CONCURRENCY, doSomethingAsync, putMoreData );
function putMoreData(queue) {
if (++i <= WORKS_TO_LAUNCH) {
console.log('Pushing to queue');
queue.push(i);
}
}
function doSomethingAsync(task, done) {
setTimeout(function() {
console.log('done ' + task);
done();
}, 1000 + task * TIMEOUT);
}
q.push(i);
I don't give this as solved because I don't know if there is a more simple approach and I want to work the complete solution, don't know if I'll find some issues when working with this and streams.