How can I keep it running after response?

I’m building a worker, where it will validate the request from IP and it will also on each request add +1 in my KV. It works something like this

const sumKeyValue = async () => {
    const s = new KeyValueService(ip, id);
    await s.sum(request.headers.get('User-Agent'));
}

const request = async () => {
    const s = new KeyValueService(ip);
    const exists = await s.findIP(ip);

    if (exists) {
        return new Response('', { status: 401 });
    }

    const res = await fetch(request);
    const text = await res.text();
    return new Response(`${text}${append.join('')}}`.trim(), { ...options, status: res.status });
}


const handleRequest = async (request: any) => {
  if (!id) {
        return fetch(request);
    }
    sumKeyValue();
    return response();
};

So, when it’s time to add +1 in the KV, even being async operation the worker should not wait to delivery the response. That’s why I did not put await sumKeyValue().

But, it did not work as expect. The sum only works sometimes, like when I access the URL 10 times, it will sum only 2 or 1. I could not figure it out where the problem is.

I also tried to follow the example, but nothing have change.

What could I be missing here?

Workers KV is eventually consistent, which means that you can lose updates to your counter. For example, consider two requests coming in at the same time:

  1. Request 1 comes in, looks at KV, sees a zero
  2. Request 2 comes in, looks at KV, sees a zero
  3. Request 1 adds 1 to zero and writes a 1 to KV
  4. Request 2 adds 1 to zero and writes a 1 to KV

You now only have 1, even though you wrote two times.

The feature you’d need to implement this properly is sometimes called an “atomic counter” or “atomic increment.” It’s something we’d like to offer someday, but do not currently.

1 Like

Oh I see…

Well I think of something else, but thanks.

I got similar problems and I found the e.waitUntil could be used. It accepts a Promise and prevent your script to be terminated before the promise resolves.

This is NOT a solution, if someone in China add +1 to counter and someone in Europe add +1 to counter it can take up to a few minutes before the value is synced, plus, if you do this in parallel you’ll have no idea what the “real” number is. If you need to do counters, you have to use an ACID database like FaunaDB.

Always test requests in parallel (load testing) before assuming that a distributed database will behave as you expect, in most cases it will not. There are a lot of hidden problems that might not be obvious, like function behaving like globals if you don’t instantiate a new class on every new request. What happens then is that the global will be overwritten with the data from a different users request.

1 Like