client/bill/monitor.go
func (m *Monitor) Run() error {
	m.mtx.Lock()
	if m.exit != nil {
		m.mtx.Unlock()
		return ErrAlreadyRunning
	}
	m.exit = make(chan struct{}, 1)
	m.exited = make(chan struct{}, 1)
	m.mtx.Unlock()

	period := time.Duration(m.conf.CollectPeriod) * time.Millisecond
L:
	for {
		select {
		case <-m.exit:
			break L
		default:
		}

		started := time.Now()

		chans, err := m.db.SelectAllFrom(data.ChannelTable, `
			 JOIN accounts ON eth_addr = client
			WHERE service_status IN ('active', 'suspended')
			  AND channel_status = 'active' AND in_use`)
		if err != nil {
			m.logger.Error(err.Error())
			break L
		}

		for _, v := range chans {
			err := m.processChannel(v.(*data.Channel))

			select {
			case m.processErrors <- err:
			default:
			}

			if err != nil {
				break L
			}
		}

		time.Sleep(period - time.Now().Sub(started))
	}

	m.exited <- struct{}{}

	m.mtx.Lock()
	m.exit = nil
	m.mtx.Unlock()

	m.logger.Info(ErrMonitorClosed.Error())
	return ErrMonitorClosed
}
func (m *Monitor) Run() error {
	m.mtx.Lock()
	if m.exit != nil {
		m.mtx.Unlock()
		return ErrAlreadyRunning
	}
	m.exit = make(chan struct{}, 1)
	m.exited = make(chan struct{}, 1)
	m.mtx.Unlock()

	period := time.Duration(m.conf.CollectPeriod) * time.Millisecond
L:
	for {
		select {
		case <-m.exit:
			break L
		default:
		}

		started := time.Now()

		chans, err := m.db.SelectAllFrom(data.ChannelTable, `
			 JOIN accounts ON eth_addr = client
			WHERE service_status IN ('active', 'suspended')
			  AND channel_status = 'active' AND in_use`)
		if err != nil {
			m.logger.Error(err.Error())
			break L
		}

		for _, v := range chans {
			err := m.processChannel(v.(*data.Channel))

			select {
			case m.processErrors <- err:
			default:
			}

			if err != nil {
				break L
			}
		}

		time.Sleep(period - time.Now().Sub(started))
	}

	m.exited <- struct{}{}

	m.mtx.Lock()
	m.exit = nil
	m.mtx.Unlock()

	m.logger.Info(ErrMonitorClosed.Error())
	return ErrMonitorClosed
}
// Run processes billing for active client channels. This function does not
// return until an error occurs or Close() is called.