crono 1.1.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +2 -3
  3. data/Rakefile +3 -4
  4. data/app/assets/javascripts/crono/materialize.min.js +6 -0
  5. data/app/assets/stylesheets/crono/application.css +26 -0
  6. data/app/assets/stylesheets/crono/materialize.min.css +31 -0
  7. data/app/controllers/crono/application_controller.rb +5 -0
  8. data/app/controllers/crono/jobs_controller.rb +11 -0
  9. data/app/models/crono/application_record.rb +5 -0
  10. data/{lib/crono/orm/active_record → app/models/crono}/crono_job.rb +1 -2
  11. data/app/views/crono/jobs/index.html.erb +50 -0
  12. data/app/views/crono/jobs/show.html.erb +16 -0
  13. data/app/views/layouts/crono/application.html.erb +31 -0
  14. data/{exe → bin}/crono +0 -0
  15. data/config/routes.rb +4 -0
  16. data/lib/crono/cli.rb +3 -20
  17. data/lib/crono/config.rb +2 -3
  18. data/lib/crono/engine.rb +15 -0
  19. data/lib/crono/job.rb +10 -6
  20. data/lib/crono/performer_proxy.rb +2 -2
  21. data/lib/crono/period.rb +6 -5
  22. data/lib/crono/time_of_day.rb +2 -2
  23. data/lib/crono/version.rb +1 -1
  24. data/lib/crono.rb +3 -3
  25. data/lib/generators/crono/install/install_generator.rb +12 -1
  26. data/lib/generators/crono/install/templates/migrations/create_crono_jobs.rb +2 -6
  27. data/spec/assets/bad_cronotab.rb +12 -0
  28. data/spec/assets/good_cronotab.rb +9 -0
  29. data/spec/cli_spec.rb +109 -0
  30. data/spec/config_spec.rb +47 -0
  31. data/spec/crono_spec.rb +7 -0
  32. data/spec/cronotab_spec.rb +20 -0
  33. data/spec/internal/:memory +0 -0
  34. data/{log/.keep → spec/internal/app/assets/config/manifest.js} +0 -0
  35. data/spec/internal/app/controllers/application_controller.rb +3 -0
  36. data/spec/internal/app/controllers/pages_controller.rb +5 -0
  37. data/spec/internal/app/views/pages/index.html.erb +1 -0
  38. data/spec/internal/config/application.rb +22 -0
  39. data/spec/internal/config/boot.rb +5 -0
  40. data/spec/internal/config/database.yml +3 -0
  41. data/spec/internal/config/environment.rb +2 -0
  42. data/spec/internal/config/routes.rb +3 -0
  43. data/spec/internal/config/storage.yml +3 -0
  44. data/spec/internal/db/crono_test.sqlite +0 -0
  45. data/spec/internal/db/schema.rb +10 -0
  46. data/spec/internal/log/test.log +3868 -0
  47. data/{tmp/.gitkeep → spec/internal/public/favicon.ico} +0 -0
  48. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/-5/-5qRtN26mFn5ud6yyw5E5MpFhT61YcDJPMTlAoDLkEs.cache +2 -0
  49. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/-C/-C4fFLLfC1HB9flvtZbgPTj9oNiDtq1bvp8LPbnRv1k.cache +0 -0
  50. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/01/01tpm-y3svQKpsPvOHFWMxWBaG_35EVrgmnB5HKppZw.cache +1 -0
  51. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/0K/0KEVKDTACcfyL6Fl5QZ6qSNOeswfd6FloUlWXQvwsHg.cache +0 -0
  52. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/1F/1FwwOzgRWJEUxIctLIsrhuh9z3QKl1XWDCcdfRhgKPk.cache +2 -0
  53. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/1n/1n5Wp1qC4BYhgEaXBnkRpO1N0oVAwLVdn47Ebk5nduY.cache +1 -0
  54. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/22/22NEh4OGcNmK5Qh9ss73s622T6309DH8zv5ABF6-6Uk.cache +0 -0
  55. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/2n/2nEu77IGZHZPjlliLtJofREUZgmt-DGEhQnGIDMd0vA.cache +1 -0
  56. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/2q/2qyBEUowJIKm_1EF_tbDWLjGDvVCbTjiHtRX_PEVn-U.cache +1 -0
  57. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/3k/3khLNNSEoPg-2idoNmihX2Ba1loklzJsXvSRXujPaRk.cache +1 -0
  58. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/7A/7A_YhyGyNk4Me5J0-p-XwK0qelTclb_2WX5pq0eY9dY.cache +1 -0
  59. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/8d/8daZARHc9PDr5TZ5fqfR-_vJ5kCRzsZQKhQxFkrg_XI.cache +0 -0
  60. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/90/90vzKM32bOX3CR_IP7i2_AHgZSmn82XN_9gLyqidtUc.cache +2 -0
  61. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/9V/9V7dOKixQfEwAEIweL7rD4CUSL51MqiMeB67I5xhwXs.cache +0 -0
  62. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/9a/9aYqlHyIyZYckdfIJ3GbxrCRrsRgbc0wfZBCfd1lVWE.cache +0 -0
  63. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Ac/AcdbxQ2RjSGjrVJSdCjS-HN_RI3GZbW86dZGhSD8Ots.cache +0 -0
  64. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Cj/Cjzu7j1PyqHJD0alH5TiAYfJDN0Zbxhg4zFZegEzuYM.cache +3 -0
  65. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/DC/DC_euXbiKWPXx4qSkPGLNU4C2RIvjMBWliBrTgl6Mqo.cache +1 -0
  66. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Db/DboywI_AoqjU7aQB5p90ZP76JW8sinmm4tMgjEG8Iu8.cache +1 -0
  67. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Dz/DzN3uO_usT53JAsXp4Td8TcNu4kjXPgqTUbLJUG7220.cache +0 -0
  68. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/F3/F3BxEXMKcd4KO0HPnLrN1g6pJIJ_iQXCz9vW--uEixY.cache +1 -0
  69. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/FE/FEVuJQTU_YF19u2IzUvuuYlUOoKsyk4JA9kX5UCIelU.cache +2 -0
  70. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/GG/GGT27f9SL2RsHpi8_pEJ1NHNgLBqDui3sDZOTgeD8z0.cache +0 -0
  71. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Gj/Gj2Go21wf2SZAnyJXKNSGfiGzYXAtrIdSHB2wuGrB6k.cache +0 -0
  72. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Hi/HicniSJ1JdM-SmZBY-KtuXL6pubtiugbtOJ-qF07hfk.cache +1 -0
  73. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Hm/HmvhHkuG82Y4O19j_mfQOw9Q4VEq5hW1Ny0Pzh3gY00.cache +3 -0
  74. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Ic/IcQIS6wTKG3ZKN6foQYUMxNU4dNQRhrAdwVrAi8u11k.cache +0 -0
  75. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Kz/KzqcEtJH4QmChDeq7W5WHCOe_NOjqNrAWOzOI0b0RrU.cache +0 -0
  76. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/LE/LE5Is_h8o9DKajRisizRsovSfpVc8T-Z_xScq0YxBMg.cache +1 -0
  77. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Mc/Mcvqw-yzpBv2GpUMmKfPZed-6wXUYd8rDdGJ12xAEsA.cache +0 -0
  78. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Nn/NneCOb3TsKS1FT6ImmBbFe5UuI_LxAmaYyk5o3st8jc.cache +1 -0
  79. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/Ro/RogqNsDfrMolvoqWLn8lCbweCzxIhN-fgXnLfBMFo8A.cache +0 -0
  80. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/T9/T9uigSdiu4wxaUieqeBq4uQYRdwGsT2acN15p0osfMU.cache +3 -0
  81. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/TH/THqp0Tr7zg3pz3WISBe0_u-QcPXHIesH0WlH_6zKzco.cache +1 -0
  82. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/VF/VFaPzl3--nBqsNzvUgJUt2TjANPLzaelSx_eOc_J090.cache +1 -0
  83. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/XG/XG0dD9kx-qBYVC-WwhzECOTsSICqvnAqLOCq1JWWrRI.cache +2 -0
  84. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/ZT/ZTJFqWngu6gOr5GuiqAV52YNHRuJeuwQelNDhtm8pKU.cache +1 -0
  85. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/ZT/zT_x9gWE8eLO9s8Ul_dtwvAqzekg3DpeuSRkQepkKJ4.cache +2 -0
  86. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/aW/aWSe6QsJ8Dk7ZAuTOYgjegrAoC2XYQtCCeo9KVzVVQs.cache +2 -0
  87. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/at/ataSdIHBESkY5GN7sMG-XyOftCkIWDK0QaKEewVkqIU.cache +2 -0
  88. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/au/aukwvh3eZhFFGyc5qZWT9KMJQHxFrTDEqfjXr4VM4dc.cache +3 -0
  89. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/bu/bu6XdfzbXfiTnSQ_6Shml3tpB7ovoUAcuCGNs-eYehI.cache +3 -0
  90. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/c2/c2yubRDZmdi6tFc__QitGtUTkpKt0Goc7FNKhRNw0Uk.cache +2 -0
  91. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/fu/fuVeiMpLNyElLwjOR6EBQP7-ZUwuJTsQe_Ie11TlX7Y.cache +3 -0
  92. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/hY/hY9drCAzyxN-KBhXav5VLmk4-AFlKT2yguKNLm7wGsA.cache +3 -0
  93. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/hg/hgkvHB4OV3E0Gq-Ud_lH2ljTzyb-8nGquMAFTBr4O0o.cache +2 -0
  94. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/jV/jVXcSpsjtyBHtJaFkxwLVcVm79OT5CVEA9XuzV01O2o.cache +2 -0
  95. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/kK/kKAy2xIb8ozBaCVqr7LkIsO3-78l5U08uq1Ot7JvES0.cache +0 -0
  96. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/kU/kUed8S8DBmWvnTdMtg0PzTYj51Rbq9R9yfr6bhPzp2I.cache +1 -0
  97. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/kw/kwNFhW24nxXy_HfVKYdXJyRqhu7ljgl9wR2DcJUo-nA.cache +3 -0
  98. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/ls/ls-nV5B50MgpIYfcYZWWWjiNsU2tD2DrEbiiEmGtArk.cache +0 -0
  99. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/m4/m47fbWgjCvvfU0XLMaGJE1zb9zh2STuMZFp7umYjLTA.cache +1 -0
  100. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/m_/m_VPZpr_Dhvko_jzP2-4VRhDpknOtciX8pqAq3jY4P8.cache +3 -0
  101. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/n5/n5rslESPawJxj7Ii3QNWxFl-2sUJE4leiEyzbuFE9Mc.cache +1 -0
  102. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/nz/nzkJWHKhKCtwI9w3TBcwyGzKEik4UFYwulf2jO7xPXc.cache +2 -0
  103. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/o4/o42lMuA3eKF-eY5RsJO4kHIGfba2QHOCO0b9rz5iNIU.cache +0 -0
  104. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/oF/oFrXjOEKX9hseSPY19vWwGHfET4QpdjGD5UdFIEN8mo.cache +0 -0
  105. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/od/od3K7nGVNq7YsrTVF7ItWWkHs8F_XEGn_BlCD5wW_gc.cache +1 -0
  106. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/qo/qoEv51qzi0h4mpNP5B4vQydW2FmhC_vbbx6vWJ99Jls.cache +1 -0
  107. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/tQ/tQ-nAfm23F-ckwkWPuftbJS6tumDQhNxQgPIZSrfPM0.cache +1 -0
  108. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/tr/trn1zjMZoBOIgSYgI84OzddhfICB2KnU4XbV8axLVGo.cache +1 -0
  109. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/u3/u3VRW5zPBM7BcNRi3G4B8M6CdscKSLJ3xYmp44ekmjU.cache +0 -0
  110. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/uG/UgcLSZ8AKbE1AYf75cSUXI6uefPECNfBcVQ7L0BDzHg.cache +3 -0
  111. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/uG/uGhNDzX7DxymN3xqHLHTndSae3bN0A-MlTk05m6wV4A.cache +1 -0
  112. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/wF/wFT7zoeQQwz-V8syWaS01xr7xgZWr3UNQLWbYSKXirw.cache +1 -0
  113. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/wN/wNw4kAG0E_RrvLeFAizMmTp_0jh-HGw1ONLtRyw92z0.cache +2 -0
  114. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/x-/x-qCUFpNxK1jTHH2qV_VgVk_KrGKdHzNGOnDMVFstuQ.cache +1 -0
  115. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/yk/ykU9I1MzGh7clO4pu853ZKl4LtMlDtyr8BjpiozFQ8E.cache +2 -0
  116. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/yk/ykWLbyEuqa0JHcwHJ-SdVxv4ImwnymlVxvbPKtk6HUM.cache +1 -0
  117. data/spec/internal/tmp/cache/assets/sprockets/v4.0.0/zO/zOr1jCikukgv8-bNHvK43vGLa3CSjtmiwf2K7dUjTnw.cache +0 -0
  118. data/spec/job_spec.rb +183 -0
  119. data/spec/models/crono/crono_job_spec.rb +31 -0
  120. data/spec/performer_proxy_spec.rb +39 -0
  121. data/spec/period_spec.rb +141 -0
  122. data/spec/rails_helper.rb +89 -0
  123. data/spec/scheduler_spec.rb +62 -0
  124. data/spec/spec_helper.rb +19 -0
  125. data/spec/tasks/crono_tasks_spec.rb +23 -0
  126. data/spec/web_spec.rb +61 -0
  127. metadata +233 -68
  128. data/.gitignore +0 -10
  129. data/.rspec +0 -2
  130. data/.travis.yml +0 -14
  131. data/Changes.md +0 -88
  132. data/Gemfile +0 -4
  133. data/Gemfile.lock +0 -78
  134. data/NOTICE +0 -2
  135. data/README.md +0 -218
  136. data/bin/console +0 -14
  137. data/bin/setup +0 -7
  138. data/crono.gemspec +0 -34
  139. data/examples/crono_web_ui.png +0 -0
  140. data/examples/cronotab.rb +0 -14
  141. data/examples/monitrc.conf +0 -6
  142. data/lib/crono/web.rb +0 -22
  143. data/web/assets/css/custom.css +0 -19
  144. data/web/assets/css/materialize.min.css +0 -16
  145. data/web/assets/font/material-design-icons/LICENSE.txt +0 -428
  146. data/web/assets/font/material-design-icons/Material-Design-Icons.eot +0 -0
  147. data/web/assets/font/material-design-icons/Material-Design-Icons.svg +0 -751
  148. data/web/assets/font/material-design-icons/Material-Design-Icons.ttf +0 -0
  149. data/web/assets/font/material-design-icons/Material-Design-Icons.woff +0 -0
  150. data/web/assets/font/material-design-icons/Material-Design-Icons.woff2 +0 -0
  151. data/web/assets/font/roboto/Roboto-Bold.ttf +0 -0
  152. data/web/assets/font/roboto/Roboto-Bold.woff +0 -0
  153. data/web/assets/font/roboto/Roboto-Bold.woff2 +0 -0
  154. data/web/assets/font/roboto/Roboto-Light.ttf +0 -0
  155. data/web/assets/font/roboto/Roboto-Light.woff +0 -0
  156. data/web/assets/font/roboto/Roboto-Light.woff2 +0 -0
  157. data/web/assets/font/roboto/Roboto-Medium.ttf +0 -0
  158. data/web/assets/font/roboto/Roboto-Medium.woff +0 -0
  159. data/web/assets/font/roboto/Roboto-Medium.woff2 +0 -0
  160. data/web/assets/font/roboto/Roboto-Regular.ttf +0 -0
  161. data/web/assets/font/roboto/Roboto-Regular.woff +0 -0
  162. data/web/assets/font/roboto/Roboto-Regular.woff2 +0 -0
  163. data/web/assets/font/roboto/Roboto-Thin.ttf +0 -0
  164. data/web/assets/font/roboto/Roboto-Thin.woff +0 -0
  165. data/web/assets/font/roboto/Roboto-Thin.woff2 +0 -0
  166. data/web/assets/js/jquery-2.1.3.min.js +0 -4
  167. data/web/assets/js/materialize.min.js +0 -10
  168. data/web/views/dashboard.haml +0 -36
  169. data/web/views/job.haml +0 -15
  170. data/web/views/layout.haml +0 -29
data/lib/crono/job.rb CHANGED
@@ -12,7 +12,7 @@ module Crono
12
12
  def initialize(performer, period, job_args, job_options = nil)
13
13
  self.execution_interval = 0.minutes
14
14
  self.performer, self.period = performer, period
15
- self.job_args = JSON.generate(job_args)
15
+ self.job_args = JSON.generate(job_args)
16
16
  self.job_log = StringIO.new
17
17
  self.job_logger = Logger.new(job_log)
18
18
  self.job_options = job_options || {}
@@ -22,7 +22,7 @@ module Crono
22
22
 
23
23
  def next
24
24
  return next_performed_at if next_performed_at.future?
25
- Time.now
25
+ Time.zone.now
26
26
  end
27
27
 
28
28
  def description
@@ -37,7 +37,7 @@ module Crono
37
37
  return Thread.new {} if perform_before_interval?
38
38
 
39
39
  log "Perform #{performer}"
40
- self.last_performed_at = Time.now
40
+ self.last_performed_at = Time.zone.now
41
41
  self.next_performed_at = period.next(since: last_performed_at)
42
42
 
43
43
  Thread.new { perform_job }
@@ -76,7 +76,11 @@ module Crono
76
76
  end
77
77
 
78
78
  def perform_job
79
- performer.new.perform *JSON.parse(job_args)
79
+ if job_args
80
+ performer.new.perform(JSON.parse(job_args))
81
+ else
82
+ performer.new.perform
83
+ end
80
84
  rescue StandardError => e
81
85
  handle_job_fail(e)
82
86
  else
@@ -86,7 +90,7 @@ module Crono
86
90
  end
87
91
 
88
92
  def handle_job_fail(exception)
89
- finished_time_sec = format('%.2f', Time.now - last_performed_at)
93
+ finished_time_sec = format('%.2f', Time.zone.now - last_performed_at)
90
94
  self.healthy = false
91
95
  log_error "Finished #{performer} in #{finished_time_sec} seconds"\
92
96
  " with error: #{exception.message}"
@@ -94,7 +98,7 @@ module Crono
94
98
  end
95
99
 
96
100
  def handle_job_success
97
- finished_time_sec = format('%.2f', Time.now - last_performed_at)
101
+ finished_time_sec = format('%.2f', Time.zone.now - last_performed_at)
98
102
  self.healthy = true
99
103
  log "Finished #{performer} in #{finished_time_sec} seconds"
100
104
  end
@@ -7,8 +7,8 @@ module Crono
7
7
  @job_args = job_args
8
8
  end
9
9
 
10
- def every(period, *args)
11
- @job = Job.new(@performer, Period.new(period, *args), @job_args, @options)
10
+ def every(period, **options)
11
+ @job = Job.new(@performer, Period.new(period, **options), @job_args, @options)
12
12
  @scheduler.add_job(@job)
13
13
  self
14
14
  end
data/lib/crono/period.rb CHANGED
@@ -27,7 +27,7 @@ module Crono
27
27
  @next = @next.beginning_of_week.advance(days: @on) if @on
28
28
  @next = @next.change(time_atts)
29
29
  return @next if @next.future?
30
- Time.now
30
+ Time.zone.now
31
31
  end
32
32
 
33
33
  def description
@@ -47,8 +47,8 @@ module Crono
47
47
  end
48
48
 
49
49
  def initial_day
50
- return Time.now unless @on
51
- day = Time.now.beginning_of_week.advance(days: @on)
50
+ return Time.zone.now unless @on
51
+ day = Time.zone.now.beginning_of_week.advance(days: @on)
52
52
  day = day.change(time_atts)
53
53
  return day if day.future?
54
54
  @period.from_now.beginning_of_week.advance(days: @on)
@@ -68,7 +68,7 @@ module Crono
68
68
 
69
69
  case at
70
70
  when String
71
- time = Time.parse(at)
71
+ time = Time.zone.parse(at)
72
72
  return time.hour, time.min
73
73
  when Hash
74
74
  return at[:hour], at[:min]
@@ -78,7 +78,8 @@ module Crono
78
78
  end
79
79
 
80
80
  def time_atts
81
- { hour: @at_hour, min: @at_min }.compact
81
+ atts = { hour: @at_hour, min: @at_min }
82
+ atts.respond_to?(:compact) ? atts.compact : atts.select { |_, value| !value.nil? }
82
83
  end
83
84
  end
84
85
  end
@@ -8,8 +8,8 @@ module Crono
8
8
  def self.parse(value)
9
9
  time =
10
10
  case value
11
- when String then Time.parse(value).utc
12
- when Hash then Time.now.change(value).utc
11
+ when String then Time.zone.parse(value).utc
12
+ when Hash then Time.zone.now.change(value).utc
13
13
  when Time then value.utc
14
14
  else
15
15
  fail "Unknown TimeOfDay format: #{value.inspect}"
data/lib/crono/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Crono
2
- VERSION = '1.1.2'
2
+ VERSION = '2.0.0'
3
3
  end
data/lib/crono.rb CHANGED
@@ -2,8 +2,11 @@
2
2
  module Crono
3
3
  end
4
4
 
5
+ require 'rails'
6
+ require 'sprockets/railtie'
5
7
  require 'active_support/all'
6
8
  require 'crono/version'
9
+ require 'crono/engine'
7
10
  require 'crono/logging'
8
11
  require 'crono/period'
9
12
  require 'crono/time_of_day'
@@ -13,7 +16,4 @@ require 'crono/scheduler'
13
16
  require 'crono/config'
14
17
  require 'crono/performer_proxy'
15
18
  require 'crono/cronotab'
16
- require 'crono/orm/active_record/crono_job'
17
19
  require 'crono/railtie' if defined?(Rails)
18
-
19
- Crono.autoload :Web, 'crono/web'
@@ -21,7 +21,18 @@ module Crono
21
21
 
22
22
  def create_migrations
23
23
  migration_template 'migrations/create_crono_jobs.rb',
24
- 'db/migrate/create_crono_jobs.rb'
24
+ 'db/migrate/create_crono_jobs.rb',
25
+ migration_version: migration_version
26
+ end
27
+
28
+ def rails5?
29
+ Rails.version.start_with? '5'
30
+ end
31
+
32
+ def migration_version
33
+ if rails5?
34
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
35
+ end
25
36
  end
26
37
  end
27
38
  end
@@ -1,5 +1,5 @@
1
- class CreateCronoJobs < ActiveRecord::Migration
2
- def self.up
1
+ class CreateCronoJobs < ActiveRecord::Migration[6.1]
2
+ def change
3
3
  create_table :crono_jobs do |t|
4
4
  t.string :job_id, null: false
5
5
  t.text :log, limit: 1073741823 # LONGTEXT for MySQL
@@ -9,8 +9,4 @@ class CreateCronoJobs < ActiveRecord::Migration
9
9
  end
10
10
  add_index :crono_jobs, [:job_id], unique: true
11
11
  end
12
-
13
- def self.down
14
- drop_table :crono_jobs
15
- end
16
12
  end
@@ -0,0 +1,12 @@
1
+ # This is an example of a bad cronotab for tests
2
+
3
+ class TestJob
4
+ def perform
5
+ puts 'Test!'
6
+ end
7
+ end
8
+
9
+ # This is an error, because you can use `on` options with
10
+ # a period less than 7 days.
11
+
12
+ Crono.perform(TestJob).every 5.days, on: :sunday
@@ -0,0 +1,9 @@
1
+ # This is an example of a good cronotab for tests
2
+
3
+ class TestJob
4
+ def perform
5
+ puts 'Test!'
6
+ end
7
+ end
8
+
9
+ Crono.perform(TestJob).every 5.seconds
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+ require 'crono/cli'
3
+
4
+ describe Crono::CLI do
5
+ let(:cli) { Crono::CLI.instance }
6
+
7
+ describe '#run' do
8
+ it 'should initialize rails with #load_rails and start working loop' do
9
+ expect(cli).to receive(:load_rails)
10
+ expect(cli).to receive(:have_jobs?).and_return(true)
11
+ expect(cli).to receive(:start_working_loop)
12
+ expect(cli).to receive(:parse_options)
13
+ expect(cli).to receive(:parse_command)
14
+ expect(cli).to receive(:write_pid)
15
+ expect(Crono::Cronotab).to receive(:process)
16
+ cli.run
17
+ end
18
+
19
+ context 'should run as daemon' do
20
+ before { cli.config.daemonize = true }
21
+
22
+ it 'should initialize rails with #load_rails and start working loop' do
23
+ expect(cli).to receive(:load_rails)
24
+ expect(cli).to receive(:have_jobs?).and_return(true)
25
+ expect(cli).to receive(:start_working_loop_in_daemon)
26
+ expect(cli).to receive(:parse_options)
27
+ expect(cli).to receive(:parse_command)
28
+ expect(cli).not_to receive(:write_pid)
29
+ expect(Crono::Cronotab).to receive(:process)
30
+ cli.run
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '#parse_options' do
36
+ it 'should set cronotab' do
37
+ cli.send(:parse_options, ['--cronotab', '/tmp/cronotab.rb'])
38
+ expect(cli.config.cronotab).to be_eql '/tmp/cronotab.rb'
39
+ end
40
+
41
+ it 'should set logfile' do
42
+ cli.send(:parse_options, ['--logfile', 'log/crono.log'])
43
+ expect(cli.config.logfile).to be_eql 'log/crono.log'
44
+ end
45
+
46
+ it 'should set pidfile' do
47
+ cli.send(:parse_options, ['--pidfile', 'tmp/pids/crono.0.log'])
48
+ expect(cli.config.pidfile).to be_eql 'tmp/pids/crono.0.log'
49
+ end
50
+
51
+ it 'should set piddir' do
52
+ cli.send(:parse_options, ['--piddir', 'tmp/pids'])
53
+ expect(cli.config.piddir).to be_eql 'tmp/pids'
54
+ end
55
+
56
+ it 'should set process_name' do
57
+ cli.send(:parse_options, ['--process_name', 'crono0'])
58
+ expect(cli.config.process_name).to be_eql 'crono0'
59
+ end
60
+
61
+ it 'should set monitor' do
62
+ cli.send(:parse_options, ['--monitor'])
63
+ expect(cli.config.monitor).to be true
64
+ end
65
+
66
+ it 'should set environment' do
67
+ cli.send(:parse_options, ['--environment', 'production'])
68
+ expect(cli.config.environment).to be_eql('production')
69
+ end
70
+ end
71
+
72
+ describe '#parse_command' do
73
+
74
+ it 'should set daemonize on start' do
75
+ cli.send(:parse_command, ['start'])
76
+ expect(cli.config.daemonize).to be true
77
+ end
78
+
79
+ it 'should set daemonize on stop' do
80
+ cli.send(:parse_command, ['stop'])
81
+ expect(cli.config.daemonize).to be true
82
+ end
83
+
84
+ it 'should set daemonize on restart' do
85
+ cli.send(:parse_command, ['restart'])
86
+ expect(cli.config.daemonize).to be true
87
+ end
88
+
89
+ it 'should set daemonize on run' do
90
+ cli.send(:parse_command, ['run'])
91
+ expect(cli.config.daemonize).to be true
92
+ end
93
+
94
+ it 'should set daemonize on zap' do
95
+ cli.send(:parse_command, ['zap'])
96
+ expect(cli.config.daemonize).to be true
97
+ end
98
+
99
+ it 'should set daemonize on reload' do
100
+ cli.send(:parse_command, ['reload'])
101
+ expect(cli.config.daemonize).to be true
102
+ end
103
+
104
+ it 'should set daemonize on status' do
105
+ cli.send(:parse_command, ['status'])
106
+ expect(cli.config.daemonize).to be true
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Crono::Config do
4
+ let(:config) { Crono::Config.new }
5
+ describe '#initialize' do
6
+ it 'should initialize with default configuration options' do
7
+ ENV['RAILS_ENV'] = 'test'
8
+ @config = Crono::Config.new
9
+ expect(@config.cronotab).to be Crono::Config::CRONOTAB
10
+ expect(@config.logfile).to be Crono::Config::LOGFILE
11
+ expect(@config.piddir).to be Crono::Config::PIDDIR
12
+ expect(@config.process_name).to be Crono::Config::PROCESS_NAME
13
+ expect(@config.daemonize).to be false
14
+ expect(@config.monitor).to be false
15
+ expect(@config.environment).to be_eql ENV['RAILS_ENV']
16
+ end
17
+
18
+ describe "#pidfile" do
19
+ subject(:pidfile) { config.pidfile }
20
+
21
+ context "not explicity configured" do
22
+ context "daemonize is false" do
23
+ before { config.daemonize = false }
24
+
25
+ specify { expect(pidfile).to be_nil }
26
+ end
27
+ end
28
+
29
+ context "explicity configured" do
30
+ let(:path) { "foo/bar/pid.pid" }
31
+
32
+ before { config.pidfile = path }
33
+
34
+ specify { expect(pidfile).to eq path }
35
+
36
+ it "trys to set piddir" do
37
+ expect(config.piddir).to eq "foo/bar"
38
+ end
39
+
40
+ it "trys to set process_name" do
41
+ expect(config.process_name).to eq "pid"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Crono do
4
+ it 'has a version number' do
5
+ expect(Crono::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Crono::Cronotab do
4
+ describe '#process' do
5
+ it 'should load cronotab file' do
6
+ cronotab_path = File.expand_path('../assets/good_cronotab.rb', __FILE__)
7
+ expect(Crono.scheduler).to receive(:add_job).with(kind_of(Crono::Job))
8
+ expect {
9
+ Crono::Cronotab.process(cronotab_path)
10
+ }.to_not raise_error
11
+ end
12
+
13
+ it 'should raise error when cronotab is invalid' do
14
+ cronotab_path = File.expand_path('../assets/bad_cronotab.rb', __FILE__)
15
+ expect {
16
+ Crono::Cronotab.process(cronotab_path)
17
+ }.to raise_error
18
+ end
19
+ end
20
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery with: :exception
3
+ end
@@ -0,0 +1,5 @@
1
+ class PagesController < ApplicationController
2
+ def index
3
+ #
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ <p>Hello World</p>
@@ -0,0 +1,22 @@
1
+ require_relative 'boot'
2
+
3
+ require 'rails/all'
4
+
5
+ # Require the gems listed in Gemfile, including any gems
6
+ # you've limited to :test, :development, or :production.
7
+ Bundler.require(*Rails.groups)
8
+ require 'crono'
9
+
10
+ module Dummy
11
+ class Application < Rails::Application
12
+ config.load_defaults Rails::VERSION::STRING.to_f
13
+
14
+ # Configuration for the application, engines, and railties goes here.
15
+ #
16
+ # These settings can be overridden in specific environments using the files
17
+ # in config/environments, which are processed later.
18
+ #
19
+ # config.time_zone = "Central Time (US & Canada)"
20
+ # config.eager_load_paths << Rails.root.join("extras")
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
+
4
+ require "bundler/setup" if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/crono_test.sqlite
@@ -0,0 +1,2 @@
1
+ # Load the Rails application.
2
+ require_relative 'application'
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ root 'pages#index'
3
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ service: Disk
3
+ root: /Users/chris/Sites/_playground/crono/tmp/storage
Binary file
@@ -0,0 +1,10 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :crono_jobs do |t|
3
+ t.string :job_id, null: false
4
+ t.text :log, limit: 1_073_741_823 # LONGTEXT for MySQL
5
+ t.datetime :last_performed_at
6
+ t.boolean :healthy
7
+ t.timestamps null: false
8
+ end
9
+ add_index :crono_jobs, [:job_id], unique: true
10
+ end