code: func (s *Session) RenewPeriodic(initialTTL string, id string, q *WriteOptions, doneCh <-chan struct{}) error {
  	ctx := q.Context()
  
  	ttl, err := time.ParseDuration(initialTTL)
  	if err != nil {
  		return err
  	}
  
  	waitDur := ttl / 2
  	lastRenewTime := time.Now()
  	var lastErr error
  	for {
  		if time.Since(lastRenewTime) > ttl {
  			return lastErr
  		}
  		select {
  		case <-time.After(waitDur):
  			entry, _, err := s.Renew(id, q)
  			if err != nil {
  				waitDur = time.Second
  				lastErr = err
  				continue
  			}
  			if entry == nil {
  				return ErrSessionExpired
  			}
  
  			// Handle the server updating the TTL
  			ttl, _ = time.ParseDuration(entry.TTL)
  			waitDur = ttl / 2
  			lastRenewTime = time.Now()
  
  		case <-doneCh:
  			// Attempt a session destroy
  			s.Destroy(id, q)
  			return nil
  
  		case <-ctx.Done():
  			// Bail immediately since attempting the destroy would
  			// use the canceled context in q, which would just bail.
  			return ctx.Err()
  		}
  	}
  }
docs: // RenewPeriodic is used to periodically invoke Session.Renew on a
  // session until a doneCh is closed. This is meant to be used in a long running
  // goroutine to ensure a session stays valid.