code: func (c *RemoteClient) unlock(id string) error {
  	// this doesn't use the lock id, because the lock is tied to the consul client.
  	if c.consulLock == nil || c.lockCh == nil {
  		return nil
  	}
  
  	// cancel our monitoring goroutine
  	c.monitorCancel()
  
  	defer func() {
  		c.consulLock = nil
  
  		// The consul session is only used for this single lock, so cancel it
  		// after we unlock.
  		// The session is only created and replaced holding Client.mu, so the
  		// CancelFunc must be non-nil.
  		c.sessionCancel()
  	}()
  
  	select {
  	case <-c.lockCh:
  		return lostLockErr
  	default:
  	}
  
  	kv := c.Client.KV()
  
  	var errs error
  
  	if _, err := kv.Delete(c.Path+lockInfoSuffix, nil); err != nil {
  		errs = multierror.Append(errs, err)
  	}
  
  	if err := c.consulLock.Unlock(); err != nil {
  		errs = multierror.Append(errs, err)
  	}
  
  	// the monitoring goroutine may be in a select on the lockCh, so we need to
  	// wait for it to return before changing the value.
  	c.monitorWG.Wait()
  	c.lockCh = nil
  
  	// This is only cleanup, and will fail if the lock was immediately taken by
  	// another client, so we don't report an error to the user here.
  	c.consulLock.Destroy()
  
  	return errs
  }
docs: // the unlock implementation.
  // Only to be called while holding Client.mu