apify_scheduler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/javascripts/scheduler/application.js +19 -0
  6. data/app/assets/stylesheets/scheduler/application.css +15 -0
  7. data/app/controllers/apify/scheduler/application_controller.rb +6 -0
  8. data/app/controllers/apify/scheduler/histories_controller.rb +24 -0
  9. data/app/controllers/apify/scheduler/servers_controller.rb +71 -0
  10. data/app/controllers/apify/scheduler/units_controller.rb +77 -0
  11. data/app/helpers/apify/scheduler/application_helper.rb +6 -0
  12. data/app/helpers/apify/scheduler/histories_helper.rb +4 -0
  13. data/app/helpers/apify/scheduler/servers_helper.rb +4 -0
  14. data/app/helpers/apify/scheduler/units_helper.rb +4 -0
  15. data/app/jobs/unit_performer_job.rb +10 -0
  16. data/app/models/apify/scheduler/frequency_period.rb +5 -0
  17. data/app/models/apify/scheduler/history.rb +9 -0
  18. data/app/models/apify/scheduler/server.rb +12 -0
  19. data/app/models/apify/scheduler/unit.rb +45 -0
  20. data/app/views/apify/scheduler/histories/_history.html.erb +6 -0
  21. data/app/views/apify/scheduler/histories/index.html.erb +14 -0
  22. data/app/views/apify/scheduler/servers/_form.html.erb +48 -0
  23. data/app/views/apify/scheduler/servers/edit.html.erb +6 -0
  24. data/app/views/apify/scheduler/servers/index.html.erb +46 -0
  25. data/app/views/apify/scheduler/servers/new.html.erb +5 -0
  26. data/app/views/apify/scheduler/servers/show.html.erb +35 -0
  27. data/app/views/apify/scheduler/shared/_short_history.html.erb +39 -0
  28. data/app/views/apify/scheduler/units/_form.html.erb +99 -0
  29. data/app/views/apify/scheduler/units/_unit.html.erb +27 -0
  30. data/app/views/apify/scheduler/units/edit.html.erb +6 -0
  31. data/app/views/apify/scheduler/units/index.html.erb +37 -0
  32. data/app/views/apify/scheduler/units/new.html.erb +5 -0
  33. data/app/views/apify/scheduler/units/show.html.erb +36 -0
  34. data/app/views/layouts/apify/scheduler/_flash.html.erb +32 -0
  35. data/app/views/layouts/apify/scheduler/application.html.erb +37 -0
  36. data/config/routes.rb +15 -0
  37. data/db/migrate/20150104005044_create_apify_scheduler_units.rb +24 -0
  38. data/db/migrate/20150105225841_create_apify_servers.rb +14 -0
  39. data/db/migrate/20150105234957_create_apify_histories.rb +13 -0
  40. data/db/migrate/20150112223842_create_frequency_periods.rb +9 -0
  41. data/lib/apify_scheduler.rb +6 -0
  42. data/lib/apify_scheduler/engine.rb +16 -0
  43. data/lib/apify_scheduler/version.rb +5 -0
  44. data/lib/tasks/resque.rake +2 -0
  45. data/lib/tasks/scheduler_tasks.rake +4 -0
  46. data/test/controllers/apify/histories_controller_test.rb +51 -0
  47. data/test/controllers/apify/names_controller_test.rb +51 -0
  48. data/test/controllers/apify/servers_controller_test.rb +51 -0
  49. data/test/controllers/apify/units_controller_test.rb +51 -0
  50. data/test/dummy/README.rdoc +28 -0
  51. data/test/dummy/Rakefile +6 -0
  52. data/test/dummy/app/assets/javascripts/application.js +13 -0
  53. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  54. data/test/dummy/app/controllers/application_controller.rb +5 -0
  55. data/test/dummy/app/helpers/application_helper.rb +2 -0
  56. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  57. data/test/dummy/bin/bundle +3 -0
  58. data/test/dummy/bin/rails +4 -0
  59. data/test/dummy/bin/rake +4 -0
  60. data/test/dummy/config.ru +4 -0
  61. data/test/dummy/config/application.rb +23 -0
  62. data/test/dummy/config/boot.rb +5 -0
  63. data/test/dummy/config/database.yml +25 -0
  64. data/test/dummy/config/environment.rb +5 -0
  65. data/test/dummy/config/environments/development.rb +37 -0
  66. data/test/dummy/config/environments/production.rb +78 -0
  67. data/test/dummy/config/environments/test.rb +39 -0
  68. data/test/dummy/config/initializers/assets.rb +8 -0
  69. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  70. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  71. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  72. data/test/dummy/config/initializers/inflections.rb +16 -0
  73. data/test/dummy/config/initializers/mime_types.rb +4 -0
  74. data/test/dummy/config/initializers/session_store.rb +3 -0
  75. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  76. data/test/dummy/config/locales/en.yml +23 -0
  77. data/test/dummy/config/routes.rb +4 -0
  78. data/test/dummy/config/secrets.yml +22 -0
  79. data/test/dummy/public/404.html +67 -0
  80. data/test/dummy/public/422.html +67 -0
  81. data/test/dummy/public/500.html +66 -0
  82. data/test/dummy/public/favicon.ico +0 -0
  83. data/test/fixtures/apify/histories.yml +11 -0
  84. data/test/fixtures/apify/servers.yml +11 -0
  85. data/test/fixtures/apify/units.yml +11 -0
  86. data/test/helpers/apify/histories_helper_test.rb +6 -0
  87. data/test/helpers/apify/names_helper_test.rb +6 -0
  88. data/test/helpers/apify/servers_helper_test.rb +6 -0
  89. data/test/helpers/apify/units_helper_test.rb +6 -0
  90. data/test/integration/navigation_test.rb +10 -0
  91. data/test/models/apify/history_test.rb +9 -0
  92. data/test/models/apify/server_test.rb +9 -0
  93. data/test/models/apify/unit_test.rb +9 -0
  94. data/test/scheduler_test.rb +7 -0
  95. data/test/test_helper.rb +17 -0
  96. metadata +231 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51bf7810d570a6b2fb56a8fa8a9897f4ef09ef72
4
+ data.tar.gz: 81fad9bc1450907abe21caf16de8e4e345125390
5
+ SHA512:
6
+ metadata.gz: 611a01092d6e1c01b8360f8482ccf9192108c80ce115db067f4674dddeb99368264930d3df512bdace186d6f199934e1a7929c242786c405afca25fedafc4825
7
+ data.tar.gz: a7bf58a72c8e41dd730e7574ae15082f5c86da4d91dc03623cf5beaeeb9a9d50070a70e83ca1f1a0a9e46e26531aa5f9eded6556f9e7fe43c13c02958b83a358
@@ -0,0 +1,20 @@
1
+ Copyright 2015 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Scheduler
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Apify Scheduler'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,19 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+
16
+
17
+ $('.message .close').on('click', function() {
18
+ $(this).closest('.message').fadeOut();
19
+ });
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_self
14
+ *
15
+ */
@@ -0,0 +1,6 @@
1
+ module Apify
2
+ module Scheduler
3
+ class ApplicationController < ActionController::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,24 @@
1
+ module Apify::Scheduler
2
+ class HistoriesController < ApplicationController
3
+ layout 'apify/scheduler/application'
4
+ before_action :set_history, only: [:destroy]
5
+
6
+ # GET /histories
7
+ def index
8
+ @unit = Unit.find(params[:unit_id])
9
+ @histories = @unit.histories.order('created_at DESC')
10
+ end
11
+
12
+ # DELETE /histories/1
13
+ def destroy
14
+ @history.destroy
15
+ redirect_to :back, notice: 'History was successfully destroyed.'
16
+ end
17
+
18
+ private
19
+ # Use callbacks to share common setup or constraints between actions.
20
+ def set_history
21
+ @history = History.find(params[:id])
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,71 @@
1
+ module Apify
2
+ module Scheduler
3
+ class ServersController < ApplicationController
4
+ layout 'apify/scheduler/application'
5
+ before_action :set_server, only: [:show, :edit, :update, :destroy, :test]
6
+
7
+ # GET /servers
8
+ def index
9
+ @servers = Apify::Scheduler::Server.all
10
+ end
11
+
12
+ # GET /servers/1
13
+ def show
14
+ end
15
+
16
+ # GET /servers/new
17
+ def new
18
+ @server = Apify::Scheduler::Server.new
19
+ end
20
+
21
+ # GET /servers/1/edit
22
+ def edit
23
+ end
24
+
25
+ def test
26
+ response = @server.test_api_key
27
+ message = response['message']
28
+ flash_key = response['status'] == '1' ? :notice : :error
29
+
30
+ redirect_to servers_path, flash: { flash_key => message }
31
+ end
32
+
33
+ # POST /servers
34
+ def create
35
+ @server = Apify::Scheduler::Server.new(server_params)
36
+
37
+ if @server.save
38
+ redirect_to @server, notice: 'Server was successfully created.'
39
+ else
40
+ render :new
41
+ end
42
+ end
43
+
44
+ # PATCH/PUT /servers/1
45
+ def update
46
+ if @server.update(server_params)
47
+ redirect_to @server, notice: 'Server was successfully updated.'
48
+ else
49
+ render :edit
50
+ end
51
+ end
52
+
53
+ # DELETE /servers/1
54
+ def destroy
55
+ @server.destroy
56
+ redirect_to servers_url, notice: 'Server was successfully destroyed.'
57
+ end
58
+
59
+ private
60
+ # Use callbacks to share common setup or constraints between actions.
61
+ def set_server
62
+ @server = Apify::Scheduler::Server.find(params[:id])
63
+ end
64
+
65
+ # Only allow a trusted parameter "white list" through.
66
+ def server_params
67
+ params.require(:server).permit(:name, :url, :description, :api_key)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,77 @@
1
+ module Apify
2
+ module Scheduler
3
+ class UnitsController < ApplicationController
4
+
5
+ layout 'apify/scheduler/application'
6
+ before_action :set_unit, only: [:show, :edit, :update, :destroy, :perform]
7
+
8
+
9
+ # GET /units
10
+ def index
11
+ @units = Apify::Scheduler::Unit.all
12
+ end
13
+
14
+ # GET /units/1
15
+ def show
16
+ end
17
+
18
+ # GET /units/new
19
+ def new
20
+ @unit = Apify::Scheduler::Unit.new
21
+ end
22
+
23
+ # GET /units/1/edit
24
+ def edit
25
+ end
26
+
27
+ # POST /units
28
+ def create
29
+ @unit = Apify::Scheduler::Unit.new(unit_params)
30
+
31
+ if @unit.save
32
+ redirect_to @unit, notice: 'Unit was successfully created.'
33
+ else
34
+ render :new
35
+ end
36
+ end
37
+
38
+ # PATCH/PUT /units/1
39
+ def update
40
+ if @unit.update(unit_params)
41
+ redirect_to @unit, notice: 'Unit was successfully updated.'
42
+ else
43
+ render :edit
44
+ end
45
+ end
46
+
47
+ # POST /units/1/perform
48
+ def perform
49
+ worker = @unit.enqueue
50
+ message = worker ? "Successfully added #{@unit.name} unit to queue. Refresh page to see progress." : "Error occured while queuing #{@unit.name}. Try again"
51
+ flash_key = worker ? :notice : :error
52
+ redirect_to units_path, flash: { flash_key => message }
53
+ end
54
+
55
+ # DELETE /units/1
56
+ def destroy
57
+ @unit.destroy
58
+ redirect_to units_url, notice: 'Unit was successfully destroyed.'
59
+ end
60
+
61
+ private
62
+ # Use callbacks to share common setup or constraints between actions.
63
+ def set_unit
64
+ @unit = Apify::Scheduler::Unit.find(params[:id])
65
+ end
66
+
67
+ # Only allow a trusted parameter "white list" through.
68
+ def unit_params
69
+ params.require(:unit).permit( :name, :description, :pattern,
70
+ :processes, :delay, :destination,
71
+ :apify_scheduler_server_id, :apify_scheduler_frequency_period_id,
72
+ :frequency_quantity, :at)
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,6 @@
1
+ module Apify
2
+ module Scheduler
3
+ module ApplicationHelper
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ module Apify::Scheduler
2
+ module HistoriesHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Apify::Scheduler
2
+ module ServersHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Apify::Scheduler
2
+ module UnitsHelper
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ class UnitPerformerJob
2
+ @queue = :units
3
+ def self.perform(unit_id, history_id)
4
+ unit = Apify::Scheduler::Unit.find(unit_id)
5
+ history = Apify::Scheduler::History.find(history_id)
6
+ history.update(queued: true)
7
+ response = unit.perform
8
+ history.update finished_at: Time.zone.now, response_body: response
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Apify::Scheduler
2
+ class FrequencyPeriod < ActiveRecord::Base
3
+
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Apify::Scheduler
2
+ class History < ActiveRecord::Base
3
+ belongs_to :unit, class_name: 'Apify::Scheduler::Unit', foreign_key: :apify_scheduler_unit_id
4
+
5
+ def currently_working?
6
+ Resque.working.map{ |w| w.job['payload']['args'].last }.include? self.id
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module Apify::Scheduler
2
+ class Server < ActiveRecord::Base
3
+ validates :name, :url, :api_key, presence: true
4
+ has_many :units, foreign_key: :apify_scheduler_server_id
5
+
6
+ def test_api_key
7
+ test_url = "#{url.chomp('/')}/test-api-key?apify_secret=#{api_key}"
8
+ response = RestClient.post(test_url, {})
9
+ JSON.parse(response)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ module Apify::Scheduler
2
+ class Unit < ActiveRecord::Base
3
+ require 'rest_client'
4
+ require 'pry'
5
+ validates :name, :pattern, :destination, :server, presence: true
6
+ belongs_to :server, class_name: 'Apify::Scheduler::Server', foreign_key: :apify_scheduler_server_id
7
+ belongs_to :frequency_period, class_name: 'Apify::Scheduler::FrequencyPeriod', foreign_key: :apify_scheduler_frequency_period_id
8
+
9
+ has_many :histories, foreign_key: :apify_scheduler_unit_id
10
+
11
+ def currently_working?
12
+ Resque.working.map{ |w| w.job['payload']['args'].first }.include? self.id
13
+ end
14
+
15
+ def enqueue
16
+ history = histories.create
17
+ Resque.enqueue(UnitPerformerJob, self.id, history.id)
18
+ end
19
+
20
+ def perform
21
+ begin
22
+ json = pattern
23
+ server_query = ["processes=#{processes}", "delay=#{delay}", "apify_secret=#{server.api_key}"].join('&')
24
+ server_crawler_url = [server.url.chomp('/'), '/crawler'].join
25
+ server_url = [server_crawler_url, server_query].join('?')
26
+
27
+ request_resource = RestClient::Resource.new( server_url, timeout: -1, open_timeout: -1 )
28
+ request = request_resource.post json, {:content_type => :json, :accept => :json}
29
+
30
+ # TODO: record download attempts
31
+ request = JSON.parse(request).to_json
32
+
33
+ response_resource = RestClient::Resource.new( destination, timeout: -1, open_timeout: -1 )
34
+ response_resource.post request, {:content_type => :json, :accept => :json}
35
+ #rescue ActiveRecord, JSON, RestClient, Parallel, Errno, Errno::EPIPE, Errno::PIPE
36
+ rescue Exception => e
37
+ { success: 0, message: e.message}.to_json
38
+ end
39
+ end
40
+
41
+ def frequency
42
+ frequency_quantity.send(frequency_period.name.pluralize)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,6 @@
1
+ <div class='ui segment'>
2
+ <div class='ui column right aligned'>
3
+ <%= link_to raw('<i class="remove circle icon red"></i>'), history_path(history), method: :delete, 'data-confirm' => "Are you sure?" %>
4
+ </div>
5
+ <%= render 'apify/scheduler/shared/short_history', history: history %>
6
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class='ui grid'>
2
+ <div class='ui column'>
3
+ <div class='ui segment'>
4
+
5
+ <h1 class='ui header'>
6
+ <%= @unit.name %>
7
+ Histories
8
+ </h1>
9
+
10
+ <%= render @histories %>
11
+
12
+ </div>
13
+ </div>
14
+ </div>
@@ -0,0 +1,48 @@
1
+ <div class='ui grid'>
2
+ <div class='column'>
3
+ <div class='ui segment form'>
4
+
5
+ <%= form_for(@server) do |f| %>
6
+ <% if @server.errors.any? %>
7
+ <div id="error_explanation">
8
+ <h2><%= pluralize(@server.errors.count, "error") %> prohibited this server from being saved:</h2>
9
+
10
+ <ul>
11
+ <% @server.errors.full_messages.each do |message| %>
12
+ <li><%= message %></li>
13
+ <% end %>
14
+ </ul>
15
+ </div>
16
+ <% end %>
17
+
18
+ <div class="field">
19
+ <div class='ui input'>
20
+ <%= f.label :name %><br>
21
+ <%= f.text_field :name %>
22
+ </div>
23
+ </div>
24
+ <div class="field">
25
+ <div class='ui input'>
26
+ <%= f.label :url %><br>
27
+ <%= f.text_field :url %>
28
+ </div>
29
+ </div>
30
+ <div class="field">
31
+ <div class='ui input'>
32
+ <%= f.label :api_key %><br>
33
+ <%= f.text_field :api_key %>
34
+ </div>
35
+ </div>
36
+ <div class="field">
37
+ <div class='ui input'>
38
+ <%= f.label :description %><br>
39
+ <%= f.text_area :description %>
40
+ </div>
41
+ </div>
42
+ <div class="right aligned column">
43
+ <%= f.submit (@server.persisted? ? 'Update Server' : 'Create Server'), class: 'ui blue submit button' %>
44
+ </div>
45
+ <% end %>
46
+ </div>
47
+ </div>
48
+ </div>