I'm currently working on design of small web service, and I have a following feature (simplified):

After some user actions, there is a wait period (ranging from 30sec to 40h) and after it's passed, the server should update database entry for the task, unless user cancelled it during the waiting period. Executed task is quite simple, just a few calculations, but it must be delayed.

And I have no idea how to do this...

I know that similar situation happens in some browser based games, where you upgrade a building and get bonuses from it after it's finished, but I was unable to find how this feature is achieved. So, my question is, is there a "state-of-art" method of dealing with such problems in backend, or any method at all?

有帮助吗?

解决方案

You can do this a few different ways. What you ultimately do depends on your server-side stack, your permissions on the server, and the nature of the side-effects needed for the delayed event.

As I see them, your options are:

  • An "embedded" scheduled task. If you're using a service-like backend technology (like a node server), you can put timeouts right in the application. And in some cases, as with node, you could even schedule a timeout for each individual event (if it turns out being more efficient than processing an event queue in your case).
  • A separate cron job, windows task, or backgrounded process, daemon, or service. A cron job should be able to execute up to once per minute. A windows task can execute up to every 5 minutes. A background job, daemon, or service can use sleeps/waits/timeouts to do things on even shorter intervals.
  • Client-driven event processing. If no side effects are required when the data isn't actively being used (e.g., all the users who care about the value are signed out), you can avoid the overhead and complexity of regularly "upkeep" jobs by just computing certain values and/or processing events as-needed during client requests. E.g., for each request from and about UserX, get entries from "the queue" where event_fire_time <= now and event_user = UserX, and "complete" those events.

In all scenarios, be sure to lock (with transactions if using a DBMS) the records your event code is processing.

其他提示

You have to store your tasks, for instance in a db table, with at least the following informations:

  • time_to_execute: timestamp of when task was set + delay in seconds
  • to_do: things to do (this must be understandable by your backend)
  • executed: 1 if the task has been executed already, otherwise 0 (default)

Then, you need a scheduler, could be a cron, which will periodically, say every minute, query an endpoint in your backend which in turn will query the db table containing your scheduled tasks. The pseudo-code for this should be like:

my_backend_endpoint_callback():
    for task in tasks:
        if not task.executed and time_to_execute > time.now():
            result = execute_my_task(task.to_do)
            if result == 0:
                # task was properly executed
                task.executed = 1

You can then have another loop which will delete all the executed tasks, depending on whether you want to keep their trace or not.

A simple approach is to have a pending tasks table in your database.

To create a task, add a row to the table that contains the action time, and any other data needed to process the task. You have a background thread that periodically queries the table, actions any tasks that have come due, and removes completed tasks from the table.

I wouldn't describe this as "state of the art" but it is a relatively simple and reliable way to do what you need.

When a task completes, do you need to notify users? That makes things somewhat more complicated as you'd need all clients to maintain a WebSocket connection to your server, so you can push notifications.

许可以下: CC-BY-SA归因
scroll top