LockWithContext will retry a lock until the context expires or is cancelled. This will let us implement a `-lock-timeout` flag, and make use of existing contexts when applicable.