crono 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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 +12 -8
  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 +3 -7
  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
@@ -9,20 +9,20 @@ module Crono
9
9
  attr_accessor :performer, :period, :job_args, :last_performed_at, :job_options,
10
10
  :next_performed_at, :job_log, :job_logger, :healthy, :execution_interval
11
11
 
12
- def initialize(performer, period, job_args, job_options = {})
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
- self.job_options = job_options
18
+ self.job_options = job_options || {}
19
19
  self.next_performed_at = period.next
20
20
  @semaphore = Mutex.new
21
21
  end
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.0'
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,16 +1,12 @@
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
- t.text :log, limit: 4294967295 # LONGTEXT for MySQL
5
+ t.text :log, limit: 1073741823 # LONGTEXT for MySQL
6
6
  t.datetime :last_performed_at
7
7
  t.boolean :healthy
8
8
  t.timestamps null: false
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