Infite for-loop в функции init () пакета - хорошая или плохая идея? - PullRequest
0 голосов
/ 25 октября 2019

Мне было интересно, будет ли плохой идеей иметь бесконечный цикл for в функции init() пакета или следует избегать этого.

Есть ли у кого-нибудькакие-либо знания или опыт, если это можно сделать или следует избегать?

Где бы вы использовали это?

Это может быть использовано, например, для пакета, который предоставляет некоторую информацию из внешних источников, которую необходимо периодически обновлять (например, один раз в день).

Я использовал код, аналогичный приведенному ниже, но без функции «сторожевой таймер». Это означает, что init() только что запустил подпрограмму go, которая будет запускаться в фоновом режиме и запускать процесс обновления всякий раз, когда появляется tick .

К сожалению, этот механизм обновления перестал работать после aprox. 3 месяца по неизвестным причинам, но служба работала нормально, только со «старыми» данными.

Простой пример реализации

Полный пример по https://play.golang.org/p/k-GI1t9J4oP

package info

import (
  "log"
  "sync"
  "time"
)

var (
  data map[string]interface{}
  lock sync.RWMutex
)

func init() {
  // ticker channel
  ticker := time.NewTicker(1 * time.Second).C

  // "watchdog" loop
  for {
    log.Println("Starting Update Loop")
    var wg sync.WaitGroup
    wg.Add(1)

    // Start asyc update process.
    go func() {
      defer wg.Done() //notify wg when if process ends for whatever reason

      // Loop forever
      // Run when a tick is received from the `ticker` channel
      for {
        select {
        case <-ticker:
          log.Println("Update ticker received")
          err := update()
          if err != nil {
            log.Printf("ERROR: %v\n", err.Error())
          }
        }
      }
    }()

    wg.Wait()
  }
}

// internal update function that retrieves some information from some external system
func update() error {
  lock.Lock()
  defer lock.Unlock()
  log.Println("Update `data`")
  // retrieve information and update `data`
  return nil
}

// Public function to query data
func GetInformation(key string) interface{} {
  lock.RLock()
  defer lock.RUnlock()
  return data[key]
}

Код работает и отлично работает для юнит-тестов, а также работает нормально. Меня интересует долговременная стабильность (время работы от 1 года и более) и тому подобное.

1 Ответ

0 голосов
/ 25 октября 2019

Это в общем порядке, так что это технически нормально, но поведение, реализованное непосредственно в init, усложняет работу по двум причинам:

  1. Трудно проверить, так же, какчто main сложно проверить. Гораздо проще проверить, вызывает ли init другую функцию, которую затем можно проверить.
  2. Трудно рассуждать. Чем больше вещей происходит «автоматически», тем меньше смысла для любого разработчика (включая ваше будущее) в использовании этого пакета. «Хорошо, я импортировал этот пакет и использовал одну крошечную функцию, и теперь каким-то образом я перешел с 1% использования ЦП на 50%, что я сделал не так», - возникнут такие вещи, которые потребуют гораздо больше усилий, чтобы понять, чем они должны.

TL; DR нет проблем с "долгосрочной стабильностью", но, скорее всего, существует проблема долгосрочной ремонтопригодности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...