Catching errors when launching an unregistered background task

I found a very simple solution solution to the problem of background tasks defined on uplink machines that may be down: don’t use them!

Instead define the background task on the server and call the uplink function.

Background tasks defined on the server are always available, so no risk of failure when launching them.
.
The uplink functions may be missing, but the failure can be easily managed when calling them from the background task.

Here is my background task defined on the server:

@anvil.server.background_task
def start_next_uplink_machine():
  for machine in tables.app_tables.uplinkmachines.search():
    row = tables.app_tables.queue.get(uplink_machine_name=machine['machine_name'], status='Processing')
    if not row:
      function_name = f"start_uplink_process_{machine['machine_name']}"
      print(f'{datetime.datetime.now().strftime("%H:%M:%S.%f")[:-4]} Calling {function_name}')
      try:
        result = anvil.server.call(function_name)
      except Exception as e:
        print(f'{datetime.datetime.now().strftime("%H:%M:%S.%f")[:-4]} Crash: "{e}"')
      else:
        print(f'{datetime.datetime.now().strftime("%H:%M:%S.%f")[:-4]} Success: "{result}"')

The uplink function that used to be a background task is this:

@anvil.server.callable(f'start_uplink_process_{COMPUTER_NAME}')
def start_uplink_process():
  executed_rows = ['OK']
  row = get_next_request_in_queue()
  while row:
    executed_rows.append(do_something_with(row))
    row = get_next_request_in_queue()
  return '\n'.join(executed_rows)

And the uplink function that gets the next row from the queue is this:

@anvil.tables.in_transaction
def get_next_request_in_queue():
  try:
    if tables.app_tables.queue.get(status='Processing',
                                   uplink_machine_name=COMPUTER_NAME):
      return # this machine is already processing one task

    row = tables.app_tables.queue.search(tables.order_by('priority'),
                                         tables.order_by('request_time', ascending=False),
                                         status='Pending')[0]
  except IndexError:
    return # there are not pending tasks

  row.update(status='Processing',
             uplink_machine_name=COMPUTER_NAME,
             started_on=datetime.now(timezone.utc))

  return row # return the row to process
1 Like