2015-11-19 54 views
22

我想在啓動Django服務器時執行一些代碼,但我只希望它只運行一次。目前,當我啓動服務器時,它會執行兩次。 Documentation說,這可能會發生,:如何避免在Django中運行兩次的AppConfig.ready()方法

你應該把一個標誌,對你的AppConfig類,以防止應執行只有一個時間重新運行 代碼。

任何想法如何實現這一目標?下面的打印語句仍然執行兩次。

from django.apps import AppConfig 
import app.mqtt 
from apscheduler.schedulers.background import BackgroundScheduler 

class MyAppConfig(AppConfig): 
    name = 'app' 
    verbose_name = "HomeIoT" 
    run_already = False 

    def ready(self): 
     if MyAppConfig.run_already: return 
     MyAppConfig.run_already = True 
     print("Hello") 
+0

那是縮進是否正確?'ready'應該在MyAppConfig類中。 –

+1

你說得對。這只是複製/粘貼錯誤。我修好了它。 – Koooop

+2

如果使用'--noreload'運行,是否發生雙面打印? – AKX

回答

-1

嘗試使用實例變量而不是類變量。例如:

class MyAppConfig(AppConfig): 
    run_already = False 

    def ready(self): 
     if not self.run_already: 
      print('Hello, world!') 
      self.run_already = True 
+4

感謝您的建議,但不幸的是這並沒有幫助。 – Koooop

+0

這看起來與問題 – user3479125

+0

相同奇怪,但根據主要最新文檔的解決方案'在這種情況下,要麼編寫冪等方法,要麼在您的AppConfig類上放置一個標誌,以防止重新運行應該只執行一次的代碼。 ' – user3479125

2

您需要實現鎖定。這不是一個簡單的問題,因爲你正在處理進程和線程,所以解決方案不會感到自然。被警告有很多關於鎖定問題的答案,一些更簡單的方法:

文件鎖定:Ensure a single instance of an application in Linux(請注意,線程默認共享文件鎖定,因此需要擴展此答案以考慮線程)。

還有這個答案,使用名爲tendo Python包封裝在一個文件鎖的實現:https://stackoverflow.com/a/1265445/181907

的Django本身提供了一個抽象的便攜式文件django.core.files.locks鎖定工具。

2

正如Roberto提到的,如果要使用默認的auto_reload功能,則需要實現鎖定才能在通過runserver命令運行服務器時執行此操作。

Django通過線程實現它的auto_reload,因此在兩個單獨的線程中導入AppConfig,主要是'command/watch'線程和運行服務器的'reload'線程。給模塊添加一個打印語句,你會看到這個動作。 'main'線程加載AppConfig文件作爲其BaseCommand執行的一部分,然後'reload'線程在服務器啓動過程中再次加載它們。

如果您的代碼無法在這兩個線程中運行,那麼您的選項有所限制。你可以實現一個線程鎖定,以便'reload'線程不會運行就緒();你可以轉移到生產環境來運行你的服務器(例如Gunicorn安裝非常快,即使是測試也是如此);或者你可以用另一種方式調用你的方法,而不是使用ready()。

我會建議搬到適當的環境,但最好的選擇真的取決於你打電話的方法應該做什麼。

相關問題