/circuits/app/startup.py

https://bitbucket.org/prologic/circuits/ · Python · 127 lines · 114 code · 1 blank · 12 comment · 0 complexity · e1bfb764aa1c36ef08c0c2169fdd5b85 MD5 · raw file

  1. # Module: startup
  2. # Date: 21st March 2011
  3. # Author: James Mills, jamesmills at comops dot com dot au
  4. """Startup Component
  5. This module implements a ``Startup`` Component that create a unified
  6. way of creating, managing and running an application in conjunction with
  7. an environment (``circuits.app.env``). The ``Startup`` Component provides
  8. five verbs that can be passed as command-line arguments:
  9. - start -- Start the application
  10. - stop -- Stop the application
  11. - init -- Create the application environment
  12. - rehash -- Reload the application's environment
  13. - upgrade -- Upgrade the application's environment
  14. """
  15. import os
  16. import errno
  17. from time import sleep
  18. try:
  19. from signal import SIGINT, SIGHUP, SIGTERM
  20. except ImportError:
  21. # Windows doesn't share Unix's signal mechanism
  22. SIGINT = None
  23. SIGHUP = None
  24. SIGTERM = None
  25. from circuits import handler, Event, BaseComponent
  26. from .daemon import Daemon
  27. from .env import Environment
  28. from .env import Create, Load, Upgrade
  29. class Error(Exception):
  30. """Error Exception"""
  31. class Command(Event):
  32. """Command Event"""
  33. class Terminate(Event):
  34. """Terminate Event"""
  35. class Startup(BaseComponent):
  36. channel = "startup"
  37. def __init__(self, path, opts, command, env=Environment,
  38. channel=channel):
  39. super(Startup, self).__init__(channel=channel)
  40. self.path = path
  41. self.opts = opts
  42. self.command = command
  43. self.env = env(path).register(self)
  44. def _getpid(self):
  45. with open(self.config.get("general", "pidfile"), "r") as f:
  46. return int(f.read().strip())
  47. def __tick__(self):
  48. if not self.command == "start" and not self:
  49. self.stop()
  50. @handler("signal", target="*")
  51. def _on_signal(self, signal, track):
  52. if signal in (SIGINT, SIGTERM):
  53. self.fire(Terminate())
  54. @handler("environment_loaded", target="env")
  55. def _on_environment_loaded(self, *args):
  56. self.fire(Command(), self.command, self)
  57. @handler("started")
  58. def _on_started(self, component, mode):
  59. if not self.command == "init":
  60. if not os.path.exists(self.env.path):
  61. raise Error("Environment does not exist!")
  62. else:
  63. self.fire(LoadEnvironment(), target=self.env)
  64. else:
  65. if os.path.exists(self.env.path):
  66. raise Error("Environment already exists!")
  67. else:
  68. self.fire(Command(), self.command, self)
  69. @handler("start")
  70. def _on_start(self):
  71. if self.opts.daemon:
  72. pidfile = self.env.config.get("general", "pidfile", "app.pid")
  73. Daemon(pidfile, self.env.path).register(self)
  74. @handler("stop")
  75. def _on_stop(self):
  76. pid = self._getpid()
  77. try:
  78. os.kill(pid, SIGTERM)
  79. os.waitpid(pid, os.WTERMSIG(0))
  80. except OSError as e:
  81. if not e.args[0] == errno.ECHILD:
  82. raise
  83. @handler("restart")
  84. def _on_restart(self):
  85. self.fire(Command(), "stop", self.channel)
  86. sleep(1)
  87. self.fire(Command(), "start", self.channel)
  88. @handler("rehash")
  89. def _on_rehash(self):
  90. pid = self._getpid()
  91. os.kill(pid, SIGHUP)
  92. @handler("init")
  93. def _on_init(self):
  94. self.fire(CreateEnvironment(), target=self.env)
  95. @handler("upgrade")
  96. def _on_upgrade(self):
  97. self.fire(UpgradeEnvironment(), target=self.env)