1

I need to run a function with a timeout. If it didn't return within the given timeout, I need to discard it and fallback to a different method.

Following is a (greatly) simplified sample code to highlight the problem. (In reality, this is an always running, highly available application. There I first read from the cache and try to read from the database only if the cache has stale data. However, if the database query took long, I need to continue with the stale data.)

My question is, in the case where the future read timed out, do I have to handle the clean-up of the future separately (i.e. keep a copy and check if it is ready time-to-time)? or can I simply ignore it (i.e. keep the code as is).

/* DB query can be time-consuming, but the result is fresh */
string readFromDatabase(){
  // ...
  // auto dbValue = db.query("select name from users where id=" + _id);
  // ...
  return dbValue;
}

/* Cache query is instant, but the result could be stale */
string readFromLocalCache(){
  // ...
  // auto cachedVal = _cache[_id];
  // ...
  return cachedVal;
}

int getValue(){
  // Idea:
  //  - Try reading from the database.
  //  - If the db query didn't return within 1 second, fallback to the other method.
  
  using namespace std::chrono_literals;

  auto fut = std::async(std::launch::async, [&](){ return readFromDatabase(); });
  switch (fut.wait_for(1s)){
    case std::future_status::ready: // query returned within allotted time
    {
      auto freshVal = fut.get();
      // update cache
      return freshVal;
    }
    case std::future_status::timeout: // timed out, fallback ------ (*)
    {
      break;
    }
    case std::future_status::deferred: // should not be reached
    {
      break;
    }
  }
  return readFromLocalCache();
  // quetion? what happens to `fut`?
}
Anubis
  • 6,995
  • 14
  • 56
  • 87
  • as the lambda is capturing by reference you might have to wait for the future to complete if you don't want undefined behaviour (depending on what the rest of your code does) – Alan Birtles Jan 24 '22 at 08:55

1 Answers1

1

My question is, in the case where the future read timed out, do I have to handle the clean-up of the future separately (i.e. keep a copy and check if it is ready time-to-time)? or can I simply ignore it (i.e. keep the code as is).

From my personal perspective, it depends on what you want. Under your current (minimal) implementation, the getValue function will be blocked by the future's destructor(see cppreference page and some SO questions).

If you do not want the blocking behavior, there are some solutions, as proposed in this question, like:

  1. move the future to some outside scope
  2. use a detached executor and some handy code/data structure to handle the return status
  3. see if you can replace the future with some timeout support I/O operations like select/poll

etc.

user8510613
  • 1,242
  • 9
  • 27