using asyncMutex to synchronize cache access on each get call
this code keeps a concurrent map for each GetRequest => AsyncMutex. the get function gets or sets a new mutex for its enclosing GetRequest, and then acquires the mutex before it does any real work. when the work is done, it releases the permit as expected
going back to get-and-remove algorithm for ETagAwareHttpClient
the algorithm is safe because it's protected by AsyncMutex