3

I am creating a route where a data attribute called "active" is being set to true, but after an hour is set to false. I am wondering if it is possible or bad practice to call a settimeout function in the express callback. Such as;

app.get("/test", (req, res) => {

//Some code

SetTimeout(func, 3600);
});

Is this bad for scalling, if this route was hit many times would it be very expensive? Thanks in advance.

Kai Ferrall
  • 81
  • 2
  • 12
  • Where is the "active" data attribute stored? – Chris Cousins Aug 24 '18 at 04:07
  • @ChrisCousins its in a mongo database, im going to change the value within the function passed to settimeout. – Kai Ferrall Aug 24 '18 at 04:09
  • Is there one "active" data attribute, or is it on a per-user basis? So if 100 people hit this route, do they all have an active data attribute, or is there still only one? – Chris Cousins Aug 24 '18 at 04:10
  • @ChrisCousins yeah it would be on a per user basis. So im concerned about how it would be affected if many people hit the route. – Kai Ferrall Aug 24 '18 at 04:12
  • 1
    You'd be better setting an "expiresAt" timestamp field; that field would be computed (when the /test" is called, per-user) to be 3600 seconds in the future. Then any code you run that needs to know if "active" is false, would actually compare the current time with the expiresAt. – Chris Cousins Aug 24 '18 at 04:13
  • 1
    @ChrisCousins Yeah I think that is what im going to do, even though it requires more code it seems a lot more cost affective. Thanks for the help! Also shoutout Canada lol. – Kai Ferrall Aug 24 '18 at 04:22

2 Answers2

1

If you store those values in a database, then you should not create a timer per entry in node that will reset this value. Especially it if it is a lang lasting timer, Session like/related data that should last longer then a few seconds should in general not be keept in the memory of the node process.

The more frequently your site is visited, the more likely it is that you have at least one timer running at any time. As soon as this is the case you are not able to restart the application without either loosing that timer. Or you need to wait until all timers are finished and while that don't accept any new ones.

And you cannot switch to clustered mode, because then if one user calls that route twice, it might end up in two different processes, each of those processes would not know of the timeouts the other process has set.

So a better idea is to add a timestamp into the database, and one cleanup timer responsible for all entries.

t.niese
  • 39,256
  • 9
  • 74
  • 101
0

It seems you only need to set 1 timer. This assumes the 'hour' starts at the first request.

let timer = null
let data = true

app.get("/test", (req, res) => {

  //Some code
  if (!timer) {
    timer = setTimeout(() => {data=false}, 3600);
  }
});

Instead, for multiple users, you can avoid setting multiple timers by putting a timestamp in a hash and polling it per request or a separate interval timer.

// init
let timers = {}

// in request
if (!timers[user]) {
    timers[user] = new Date().getTime() / 1000 + 3600
}
else if (timers[user] <= new Date().getTime() / 1000)
{
    // update db, etc
}


// or poll for expirations in separate single timer routine
let now = new Date().getTime() / 1000
Object.keys(timers).forEach(user => {
  if (timers[user] <= now) {
    // update db, etc
  }
})
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78