code: func (do *Domain) LoadPrivilegeLoop(ctx sessionctx.Context) error {
  	ctx.GetSessionVars().InRestrictedSQL = true
  	do.privHandle = privileges.NewHandle()
  	err := do.privHandle.Update(ctx)
  	if err != nil {
  		return err
  	}
  
  	var watchCh clientv3.WatchChan
  	duration := 5 * time.Minute
  	if do.etcdClient != nil {
  		watchCh = do.etcdClient.Watch(context.Background(), privilegeKey)
  		duration = 10 * time.Minute
  	}
  
  	do.wg.Add(1)
  	go func() {
  		defer do.wg.Done()
  		defer recoverInDomain("loadPrivilegeInLoop", false)
  		var count int
  		for {
  			ok := true
  			select {
  			case <-do.exit:
  				return
  			case _, ok = <-watchCh:
  			case <-time.After(duration):
  			}
  			if !ok {
  				logutil.Logger(context.Background()).Error("load privilege loop watch channel closed")
  				watchCh = do.etcdClient.Watch(context.Background(), privilegeKey)
  				count++
  				if count > 10 {
  					time.Sleep(time.Duration(count) * time.Second)
  				}
  				continue
  			}
  
  			count = 0
  			err := do.privHandle.Update(ctx)
  			metrics.LoadPrivilegeCounter.WithLabelValues(metrics.RetLabel(err)).Inc()
  			if err != nil {
  				logutil.Logger(context.Background()).Error("load privilege failed", zap.Error(err))
  			} else {
  				logutil.Logger(context.Background()).Debug("reload privilege success")
  			}
  		}
  	}()
  	return nil
  }
docs: // LoadPrivilegeLoop create a goroutine loads privilege tables in a loop, it
  // should be called only once in BootstrapSession.