marty 0.5.15 → 0.5.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +27 -0
- data/.rspec +3 -0
- data/.travis.yml +23 -0
- data/Gemfile +23 -0
- data/INDEPENDENCE_ISSUES.md +23 -0
- data/app/assets/images/marty/.gitkeep +0 -0
- data/app/components/marty/report_form.rb +9 -4
- data/gemini_deprecations.md +6 -0
- data/lib/marty/data_change.rb +99 -0
- data/lib/marty/data_conversion.rb +11 -3
- data/lib/marty/data_exporter.rb +9 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +35 -0
- data/script/rails +8 -0
- data/spec/controllers/application_controller_spec.rb +52 -0
- data/spec/controllers/job_controller_spec.rb +226 -0
- data/spec/controllers/rpc_controller_spec.rb +379 -0
- data/spec/controllers/rpc_import_spec.rb +45 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/components_controller.rb +7 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/gemini/amortization_type.rb +5 -0
- data/spec/dummy/app/models/gemini/bud_category.rb +7 -0
- data/spec/dummy/app/models/gemini/entity.rb +2 -0
- data/spec/dummy/app/models/gemini/extras/data_import.rb +5 -0
- data/spec/dummy/app/models/gemini/extras/settlement_import.rb +28 -0
- data/spec/dummy/app/models/gemini/fannie_bup.rb +29 -0
- data/spec/dummy/app/models/gemini/grouping.rb +8 -0
- data/spec/dummy/app/models/gemini/grouping_head_version.rb +14 -0
- data/spec/dummy/app/models/gemini/head.rb +7 -0
- data/spec/dummy/app/models/gemini/head_version.rb +14 -0
- data/spec/dummy/app/models/gemini/helper.rb +44 -0
- data/spec/dummy/app/models/gemini/loan_program.rb +11 -0
- data/spec/dummy/app/models/gemini/mortgage_type.rb +5 -0
- data/spec/dummy/app/models/gemini/simple.rb +6 -0
- data/spec/dummy/app/models/gemini/streamline_type.rb +16 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +82 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml.example +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +35 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/delayed_job.rb +5 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/db/migrate/20140801000000_create_groupings.rb +11 -0
- data/spec/dummy/db/migrate/20150406171536_create_categories.rb +27 -0
- data/spec/dummy/db/migrate/20150408200916_create_loan_programs.rb +26 -0
- data/spec/dummy/db/migrate/20150408201429_create_types.rb +21 -0
- data/spec/dummy/db/migrate/20150420000001_create_heads.rb +14 -0
- data/spec/dummy/db/migrate/20150420000002_create_head_versions.rb +15 -0
- data/spec/dummy/db/migrate/20150420000003_create_grouping_head_versions.rb +12 -0
- data/spec/dummy/db/migrate/20151023000001_create_simple.rb +12 -0
- data/spec/dummy/db/seeds.rb +8 -0
- data/spec/dummy/delorean/blame_report.dl +171 -0
- data/spec/dummy/delorean/data_report.dl +105 -0
- data/spec/dummy/delorean/fields.dl +52 -0
- data/spec/dummy/delorean/styles.dl +134 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/class_list.rb +3 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/icons/READ.txt +3 -0
- data/spec/dummy/public/icons/application_cascade.png +0 -0
- data/spec/dummy/public/icons/application_delete.png +0 -0
- data/spec/dummy/public/icons/application_put.png +0 -0
- data/spec/dummy/public/icons/application_view_detail.png +0 -0
- data/spec/dummy/public/icons/arrow_in.png +0 -0
- data/spec/dummy/public/icons/arrow_refresh.png +0 -0
- data/spec/dummy/public/icons/database_save.png +0 -0
- data/spec/dummy/public/icons/door_in.png +0 -0
- data/spec/dummy/public/icons/door_out.png +0 -0
- data/spec/dummy/public/icons/group.png +0 -0
- data/spec/dummy/public/icons/page_lightning.png +0 -0
- data/spec/dummy/public/icons/printer.png +0 -0
- data/spec/dummy/public/icons/report_disk.png +0 -0
- data/spec/dummy/public/icons/report_go.png +0 -0
- data/spec/dummy/public/icons/report_magnify.png +0 -0
- data/spec/dummy/public/icons/script.png +0 -0
- data/spec/dummy/public/icons/script_add.png +0 -0
- data/spec/dummy/public/icons/script_go.png +0 -0
- data/spec/dummy/public/icons/script_key.png +0 -0
- data/spec/dummy/public/icons/table_go.png +0 -0
- data/spec/dummy/public/icons/time.png +0 -0
- data/spec/dummy/public/icons/time_add.png +0 -0
- data/spec/dummy/public/icons/time_go.png +0 -0
- data/spec/dummy/public/icons/timeline_marker.png +0 -0
- data/spec/dummy/public/icons/user_add.png +0 -0
- data/spec/dummy/public/icons/user_delete.png +0 -0
- data/spec/dummy/public/icons/user_edit.png +0 -0
- data/spec/dummy/public/icons/wrench.png +0 -0
- data/spec/dummy/script/delayed_job +6 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/features/javascripts/job_dashboard_live_search.js.coffee +8 -0
- data/spec/features/javascripts/login.js.coffee +8 -0
- data/spec/features/jobs_dashboard_netzke_spec.rb +24 -0
- data/spec/features/jobs_dashboard_spec.rb +49 -0
- data/spec/fixtures/scripts/load_tests/script1.dl +2 -0
- data/spec/fixtures/scripts/load_tests/script2.dl +2 -0
- data/spec/job_helper.rb +102 -0
- data/spec/lib/data_exporter_spec.rb +71 -0
- data/spec/lib/data_importer_spec.rb +461 -0
- data/spec/lib/xl_spec.rb +198 -0
- data/spec/lib/xl_styles_spec.rb +115 -0
- data/spec/models/api_auth_spec.rb +187 -0
- data/spec/models/posting_spec.rb +107 -0
- data/spec/models/promise_spec.rb +65 -0
- data/spec/models/script_spec.rb +187 -0
- data/spec/models/user_spec.rb +68 -0
- data/spec/requests/routes_spec.rb +12 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/clean_db_helpers.rb +18 -0
- data/spec/support/delayed_job_helpers.rb +12 -0
- data/spec/support/user_helpers.rb +12 -0
- metadata +139 -89
- data/app/components/marty/auth_app.rb~ +0 -51
- data/app/components/marty/auth_app/javascripts/auth_app.js~ +0 -91
- data/app/components/marty/cm_form_panel.rb~ +0 -5
- data/app/components/marty/cm_grid_panel.rb~ +0 -35
- data/app/components/marty/data_import_view.rb~ +0 -142
- data/app/components/marty/extras/layout.rb~ +0 -46
- data/app/components/marty/live_search_grid_panel.rb~ +0 -49
- data/app/components/marty/main_auth_app.rb~ +0 -238
- data/app/components/marty/mcfly_grid_panel.rb~ +0 -80
- data/app/components/marty/new_posting_form.rb~ +0 -46
- data/app/components/marty/new_posting_window.rb~ +0 -21
- data/app/components/marty/pivot_grid.rb +0 -52
- data/app/components/marty/pivot_grid/endpoints.rb +0 -45
- data/app/components/marty/pivot_grid/javascripts/extensions.js +0 -150
- data/app/components/marty/pivot_grid/javascripts/pivot_grid.js +0 -86
- data/app/components/marty/pivot_grid/services.rb +0 -44
- data/app/components/marty/posting_grid.rb~ +0 -140
- data/app/components/marty/promise_view.rb~ +0 -157
- data/app/components/marty/promise_view/stylesheets/promise_view.css~ +0 -15
- data/app/components/marty/report_form.rb~ +0 -217
- data/app/components/marty/report_select.rb~ +0 -133
- data/app/components/marty/reporting.rb~ +0 -39
- data/app/components/marty/script_detail.rb~ +0 -430
- data/app/components/marty/script_form.rb~ +0 -233
- data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js~ +0 -909
- data/app/components/marty/script_grid.rb~ +0 -99
- data/app/components/marty/script_tester.rb~ +0 -213
- data/app/components/marty/scripting.rb~ +0 -124
- data/app/components/marty/select_report.rb~ +0 -143
- data/app/components/marty/simple_app.rb~ +0 -101
- data/app/components/marty/tag_grid.rb~ +0 -89
- data/app/components/marty/tree_panel.rb~ +0 -256
- data/app/components/marty/tree_panel/javascripts/tree_panel.js~ +0 -317
- data/app/components/marty/user_pivot.rb +0 -128
- data/app/components/marty/user_view.rb~ +0 -188
- data/app/controllers/marty/application_controller.rb~ +0 -133
- data/app/controllers/marty/components_controller.rb~ +0 -37
- data/app/controllers/marty/job_controller.rb~ +0 -28
- data/app/controllers/marty/rpc_controller.rb~ +0 -61
- data/app/helpers/marty/script_set.rb~ +0 -59
- data/app/models/marty/api_auth.rb~ +0 -48
- data/app/models/marty/data_change.rb~ +0 -141
- data/app/models/marty/enum.rb~ +0 -16
- data/app/models/marty/import_type.rb~ +0 -48
- data/app/models/marty/poop.rb~ +0 -169
- data/app/models/marty/posting.rb~ +0 -86
- data/app/models/marty/posting_type.rb~ +0 -21
- data/app/models/marty/promise.rb~ +0 -196
- data/app/models/marty/role.rb~ +0 -10
- data/app/models/marty/script.rb~ +0 -62
- data/app/models/marty/tag.rb~ +0 -91
- data/app/models/marty/user.rb~ +0 -148
- data/app/models/marty/user_role.rb~ +0 -13
- data/app/views/layouts/marty/application.html.erb~ +0 -11
- data/config/routes.rb~ +0 -10
- data/db/migrate/019_create_marty_postings.rb~ +0 -19
- data/db/migrate/095_create_marty_tags.rb~ +0 -19
- data/lib/marty.rb~ +0 -13
- data/lib/marty/content_handler.rb~ +0 -93
- data/lib/marty/data_exporter.rb~ +0 -137
- data/lib/marty/data_importer.rb~ +0 -114
- data/lib/marty/data_row_processor.rb~ +0 -206
- data/lib/marty/drop_folder_hook.rb~ +0 -17
- data/lib/marty/folder_hook.rb~ +0 -9
- data/lib/marty/lazy_column_loader.rb~ +0 -47
- data/lib/marty/mcfly_query.rb~ +0 -188
- data/lib/marty/migrations.rb~ +0 -65
- data/lib/marty/monkey.rb~ +0 -160
- data/lib/marty/permissions.rb~ +0 -69
- data/lib/marty/promise.rb~ +0 -41
- data/lib/marty/promise_job.rb~ +0 -121
- data/lib/marty/promise_proxy.rb~ +0 -69
- data/lib/marty/util.rb~ +0 -80
- data/lib/marty/version.rb~ +0 -3
- data/lib/marty/xl.rb~ +0 -526
- data/lib/pyxll/README.txt~ +0 -16
- data/lib/pyxll/gemini.py~ +0 -110
- data/lib/pyxll/pyxll.cfg~ +0 -12
data/app/models/marty/poop.rb~
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
class Marty::Promise < Marty::Base
|
2
|
-
|
3
|
-
# default timeout (seconds) to wait for promise values
|
4
|
-
DEFAULT_PROMISE_TIMEOUT = 30
|
5
|
-
|
6
|
-
# default timeout (seconds) to wait for jobs to start
|
7
|
-
DEFAULT_JOB_TIMEOUT = 10
|
8
|
-
|
9
|
-
attr_accessible :title,
|
10
|
-
:cformat,
|
11
|
-
:parent_id,
|
12
|
-
:job_id,
|
13
|
-
:status,
|
14
|
-
:result,
|
15
|
-
:start_dt,
|
16
|
-
:end_dt
|
17
|
-
|
18
|
-
serialize :result, Hash
|
19
|
-
|
20
|
-
validates_presence_of :title
|
21
|
-
|
22
|
-
has_many :children, foreign_key: 'parent_id', class_name: "Marty::Promise"
|
23
|
-
belongs_to :parent, class_name: "Marty::Promise"
|
24
|
-
|
25
|
-
def raw_conn
|
26
|
-
self.class.connection.raw_connection
|
27
|
-
end
|
28
|
-
|
29
|
-
def pg_notify
|
30
|
-
raw_conn.async_exec("NOTIFY promise_#{id}")
|
31
|
-
end
|
32
|
-
|
33
|
-
def set_start
|
34
|
-
log "LOGLOG #{Rails.logger}"
|
35
|
-
|
36
|
-
if self.start_dt || self.result != {}
|
37
|
-
Marty::Util.logger.error("promise already started: #{self}")
|
38
|
-
return
|
39
|
-
end
|
40
|
-
|
41
|
-
# mark promise as started
|
42
|
-
self.start_dt = DateTime.now
|
43
|
-
self.save!
|
44
|
-
end
|
45
|
-
|
46
|
-
def set_result(res)
|
47
|
-
log "SETRES #{Process.pid} #{res} #{self}"
|
48
|
-
|
49
|
-
# promise must have been started and not yet ended
|
50
|
-
if !self.start_dt || self.end_dt || self.result != {}
|
51
|
-
log "SETERR #{Process.pid} #{self}"
|
52
|
-
Marty::Util.logger.error("unexpected promise state: #{self}")
|
53
|
-
return
|
54
|
-
end
|
55
|
-
|
56
|
-
raise "bad result" unless res.is_a?(Hash)
|
57
|
-
|
58
|
-
self.status = res["error"].nil?
|
59
|
-
self.result = res
|
60
|
-
|
61
|
-
# update title/format from result hash (somewhat hacky)
|
62
|
-
self.title = res["title"].to_s if res["title"]
|
63
|
-
self.cformat = res["format"].to_s if res["format"]
|
64
|
-
|
65
|
-
# mark promise as ended
|
66
|
-
self.end_dt = DateTime.now
|
67
|
-
self.save!
|
68
|
-
|
69
|
-
log "NOTIFY #{Process.pid}"
|
70
|
-
pg_notify
|
71
|
-
end
|
72
|
-
|
73
|
-
def to_s
|
74
|
-
inspect
|
75
|
-
end
|
76
|
-
|
77
|
-
def log(msg)
|
78
|
-
open('/tmp/dj.out', 'a') { |f| f.puts msg }
|
79
|
-
end
|
80
|
-
|
81
|
-
def wait_for_my_notify(timeout)
|
82
|
-
while true do
|
83
|
-
# FIXME: we keep using the same timeout. The timeout should be
|
84
|
-
# reduced by total time spent here.
|
85
|
-
n = raw_conn.wait_for_notify(timeout)
|
86
|
-
return n if !n || n=="promise_#{id}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def latest
|
91
|
-
# latest uncached version
|
92
|
-
Marty::Promise.uncached {Marty::Promise.find(id)}
|
93
|
-
end
|
94
|
-
|
95
|
-
def work_off_job(job)
|
96
|
-
# Create a temporary worker to work off the job
|
97
|
-
Delayed::Job.where(id: job.id).
|
98
|
-
update_all(locked_at: Delayed::Job.db_time_now, locked_by: "Temp")
|
99
|
-
w = Delayed::Worker.new
|
100
|
-
w.run(job)
|
101
|
-
end
|
102
|
-
|
103
|
-
def wait_for_result(timeout)
|
104
|
-
return self.result if self.result != {}
|
105
|
-
|
106
|
-
# FIXME: instead of using latest(), should look at how delayed
|
107
|
-
# jobs are loaded. i.e. use reset+reload.
|
108
|
-
|
109
|
-
begin
|
110
|
-
# start listening on promise's notification
|
111
|
-
raw_conn.exec("LISTEN promise_#{id}")
|
112
|
-
|
113
|
-
last = latest
|
114
|
-
|
115
|
-
# if job hasn't started yet, wait for it to start
|
116
|
-
if !last.start_dt
|
117
|
-
log "AAAA #{Process.pid} #{last}"
|
118
|
-
|
119
|
-
job = Delayed::Job.find_by_id(last.job_id)
|
120
|
-
job.reload if job # paranoid
|
121
|
-
|
122
|
-
if !job && job.locked_at
|
123
|
-
# job has been locked, so it looks like it started already
|
124
|
-
# and we need to wait for it.
|
125
|
-
wait_for_my_notify(Marty::Promise::DEFAULT_JOB_TIMEOUT)
|
126
|
-
else
|
127
|
-
# work off the job instead of waiting for a real worker to
|
128
|
-
# pick it up.
|
129
|
-
log "OFFF #{Process.pid} #{last}"
|
130
|
-
work_off_job(job)
|
131
|
-
end
|
132
|
-
|
133
|
-
last = latest
|
134
|
-
|
135
|
-
# we waited for it but it never started. So, mark it with a
|
136
|
-
# timeout error.
|
137
|
-
if !last.start_dt
|
138
|
-
log "TO11 #{Process.pid} #{last}"
|
139
|
-
return {"error" => "promise #{last.id} timed out (never started)"}
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# reload promise in case out copy doesn't have a result yet
|
144
|
-
last = latest unless last.end_dt
|
145
|
-
|
146
|
-
# at this point, we know the promise has already started
|
147
|
-
if !last.end_dt
|
148
|
-
wait_for_my_notify(timeout)
|
149
|
-
log "UUUU #{Process.pid} #{id} #{Time.now.to_f}"
|
150
|
-
last = latest
|
151
|
-
|
152
|
-
log "XXXX #{Process.pid} #{Time.now.to_f} #{last}"
|
153
|
-
|
154
|
-
if !last.end_dt
|
155
|
-
log "TO22 #{Process.pid} #{last}"
|
156
|
-
return {"error" => "promise #{last.id} timed out (didn't end)"}
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
log "RRRR #{Process.pid} #{last} #{Time.now.to_f}"
|
161
|
-
|
162
|
-
last.result
|
163
|
-
ensure
|
164
|
-
# Stop listening to the promise notifications
|
165
|
-
raw_conn.exec("UNLISTEN promise_#{id}")
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
class Marty::Posting < Marty::Base
|
2
|
-
has_mcfly append_only: true
|
3
|
-
|
4
|
-
mcfly_validates_uniqueness_of :name
|
5
|
-
validates_presence_of :name, :posting_type_id, :comment
|
6
|
-
|
7
|
-
belongs_to :user, class_name: "Marty::User"
|
8
|
-
belongs_to :posting_type
|
9
|
-
|
10
|
-
def self.make_name(posting_type, dt)
|
11
|
-
return 'NOW' if Mcfly.is_infinity(dt)
|
12
|
-
|
13
|
-
return unless posting_type
|
14
|
-
|
15
|
-
# If no dt is provided (which is the usual non-testing case), we
|
16
|
-
# use Time.now.strftime to name the posting. This has the effect
|
17
|
-
# of using the host's timezone. i.e. since we're in PST8PDT, names
|
18
|
-
# will be based off of the Pacific TZ.
|
19
|
-
dt ||= Time.now
|
20
|
-
"#{posting_type.name}-#{dt.strftime('%Y%m%d-%H%M')}"
|
21
|
-
end
|
22
|
-
|
23
|
-
before_validation :set_posting_name
|
24
|
-
def set_posting_name
|
25
|
-
posting_type = Marty::PostingType.find_by_id(self.posting_type_id)
|
26
|
-
self.name = self.class.make_name(posting_type, self.created_dt)
|
27
|
-
true
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.do_create(type_name, dt, comment)
|
31
|
-
posting_type = Marty::PostingType.find_by_name(type_name)
|
32
|
-
|
33
|
-
raise "unknown posting type #{name}" unless posting_type
|
34
|
-
|
35
|
-
o = new
|
36
|
-
o.posting_type = posting_type
|
37
|
-
o.comment = comment
|
38
|
-
o.created_dt = dt
|
39
|
-
o.save!
|
40
|
-
o
|
41
|
-
end
|
42
|
-
|
43
|
-
# Not using mcfly_lookup since we don't want these time-warp markers
|
44
|
-
# time-warped. FIXME: perhaps this should use mcfly_lookup since we
|
45
|
-
# may allow deletion of postings. i.e. a new one with same name
|
46
|
-
# might be created. Or, use regular validates_uniqueness_of instead
|
47
|
-
# of mcfly_validates_uniqueness_of.
|
48
|
-
delorean_fn :lookup, sig: 1 do
|
49
|
-
|name|
|
50
|
-
self.find_by_name(name)
|
51
|
-
end
|
52
|
-
|
53
|
-
delorean_fn :lookup_dt, sig: 1 do
|
54
|
-
|name|
|
55
|
-
lookup(name).try(:created_dt)
|
56
|
-
end
|
57
|
-
|
58
|
-
delorean_fn :first_match, sig: 1 do
|
59
|
-
|dt|
|
60
|
-
where("created_dt <= ?", dt).order("created_dt DESC").first
|
61
|
-
end
|
62
|
-
|
63
|
-
delorean_fn :get_latest, sig: [1, 2] do
|
64
|
-
|limit, is_test=nil|
|
65
|
-
# IMPORTANT: is_test arg is ignored (KEEP for backward compat.)
|
66
|
-
|
67
|
-
where("created_dt <> 'infinity'").
|
68
|
-
order("created_dt DESC").limit(limit).to_a
|
69
|
-
end
|
70
|
-
|
71
|
-
delorean_fn :get_last, sig: [0, 1] do
|
72
|
-
|posting_type=nil|
|
73
|
-
|
74
|
-
raise "bad posting type" if
|
75
|
-
posting_type && !posting_type.is_a?(Marty::PostingType)
|
76
|
-
|
77
|
-
q = where("created_dt <> 'infinity'")
|
78
|
-
q = q.where(posting_type_id: posting_type.id) if posting_type
|
79
|
-
q.order("created_dt DESC").first
|
80
|
-
end
|
81
|
-
|
82
|
-
delorean_fn :is_today, sig: 1 do
|
83
|
-
|posting|
|
84
|
-
posting.created_dt.to_date == Date.today
|
85
|
-
end
|
86
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
class Marty::PostingType < Marty::Base
|
2
|
-
extend Marty::Enum
|
3
|
-
|
4
|
-
<<<<<<< HEAD
|
5
|
-
# attr_accessible :name
|
6
|
-
=======
|
7
|
-
>>>>>>> master
|
8
|
-
validates_presence_of :name
|
9
|
-
validates_uniqueness_of :name
|
10
|
-
|
11
|
-
delorean_fn :lookup, sig: 1 do
|
12
|
-
|name|
|
13
|
-
self.find_by_name(name)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.seed
|
17
|
-
['BASE', 'CLOSE', 'INTRA', 'RULE'].each { |type|
|
18
|
-
create name: type
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
@@ -1,196 +0,0 @@
|
|
1
|
-
class Marty::Promise < Marty::Base
|
2
|
-
class MarshalResult
|
3
|
-
def dump(v)
|
4
|
-
Marshal.dump(v)
|
5
|
-
end
|
6
|
-
|
7
|
-
def load(v)
|
8
|
-
# FIXME: Rails4 bytea interface seems to remove the trailing
|
9
|
-
# \x00 char.
|
10
|
-
v += "\x00" if v
|
11
|
-
|
12
|
-
# Marshal.load can't handle nil
|
13
|
-
v.nil? ? {} : Marshal.load(v)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# default timeout (seconds) to wait for promise values
|
18
|
-
DEFAULT_PROMISE_TIMEOUT = Rails.configuration.marty.promise_timeout || 30
|
19
|
-
|
20
|
-
# default timeout (seconds) to wait for jobs to start
|
21
|
-
DEFAULT_JOB_TIMEOUT = Rails.configuration.marty.job_timeout || 10
|
22
|
-
|
23
|
-
lazy_load :result
|
24
|
-
|
25
|
-
serialize :result, MarshalResult.new
|
26
|
-
|
27
|
-
validates_presence_of :title
|
28
|
-
|
29
|
-
has_many :children,
|
30
|
-
foreign_key: 'parent_id',
|
31
|
-
class_name: "Marty::Promise",
|
32
|
-
dependent: :destroy
|
33
|
-
|
34
|
-
belongs_to :parent, class_name: "Marty::Promise"
|
35
|
-
belongs_to :user, class_name: "Marty::User"
|
36
|
-
|
37
|
-
def self.cleanup(all=false)
|
38
|
-
begin
|
39
|
-
where('start_dt < ? AND parent_id IS NULL',
|
40
|
-
DateTime.now - (all ? 0.hours : 2.hours)).destroy_all
|
41
|
-
rescue => exc
|
42
|
-
Marty::Util.logger.error("promise GC error: #{exc}")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def raw_conn
|
47
|
-
self.class.connection.raw_connection
|
48
|
-
end
|
49
|
-
|
50
|
-
def pg_notify
|
51
|
-
raw_conn.async_exec("NOTIFY promise_#{id}")
|
52
|
-
end
|
53
|
-
|
54
|
-
def set_start
|
55
|
-
if self.start_dt || self.result != {}
|
56
|
-
Marty::Util.logger.error("promise already started: #{self}")
|
57
|
-
return
|
58
|
-
end
|
59
|
-
|
60
|
-
# mark promise as started
|
61
|
-
self.start_dt = DateTime.now
|
62
|
-
self.save!
|
63
|
-
end
|
64
|
-
|
65
|
-
def set_result(res)
|
66
|
-
# log "SETRES #{Process.pid} #{res} #{self}"
|
67
|
-
|
68
|
-
# promise must have been started and not yet ended
|
69
|
-
if !self.start_dt || self.end_dt || self.result != {}
|
70
|
-
# log "SETERR #{Process.pid} #{self}"
|
71
|
-
Marty::Util.logger.error("unexpected promise state: #{self}")
|
72
|
-
return
|
73
|
-
end
|
74
|
-
|
75
|
-
raise "bad result" unless res.is_a?(Hash)
|
76
|
-
|
77
|
-
self.status = res["error"].nil?
|
78
|
-
self.result = res
|
79
|
-
|
80
|
-
# update title/format from result hash (somewhat hacky)
|
81
|
-
self.title = res["title"].to_s if res["title"]
|
82
|
-
self.cformat = res["format"].to_s if res["format"]
|
83
|
-
|
84
|
-
# mark promise as ended
|
85
|
-
self.end_dt = DateTime.now
|
86
|
-
self.save!
|
87
|
-
|
88
|
-
# log "NOTIFY #{Process.pid}"
|
89
|
-
pg_notify
|
90
|
-
end
|
91
|
-
|
92
|
-
def to_s
|
93
|
-
inspect
|
94
|
-
end
|
95
|
-
|
96
|
-
# def log(msg)
|
97
|
-
# open('/tmp/dj.out', 'a') { |f| f.puts msg }
|
98
|
-
# end
|
99
|
-
|
100
|
-
def wait_for_my_notify(timeout)
|
101
|
-
while true do
|
102
|
-
# FIXME: we keep using the same timeout. The timeout should be
|
103
|
-
# reduced by total time spent here.
|
104
|
-
n = raw_conn.wait_for_notify(timeout)
|
105
|
-
return n if !n || n=="promise_#{id}"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def latest
|
110
|
-
# FIXME: Not sure if this is idiomatic. What's the best way to
|
111
|
-
# force AR to reload the promise object? reset+reload doesn't
|
112
|
-
# seems to work.
|
113
|
-
|
114
|
-
# get latest uncached version
|
115
|
-
Marty::Promise.uncached {Marty::Promise.find(id)}
|
116
|
-
end
|
117
|
-
|
118
|
-
def work_off_job(job)
|
119
|
-
# Create a temporary worker to work off the job
|
120
|
-
Delayed::Job.where(id: job.id).
|
121
|
-
update_all(locked_at: Delayed::Job.db_time_now, locked_by: "Temp")
|
122
|
-
w = Delayed::Worker.new
|
123
|
-
w.run(job)
|
124
|
-
end
|
125
|
-
|
126
|
-
def wait_for_result(timeout)
|
127
|
-
return self.result if self.result != {}
|
128
|
-
|
129
|
-
begin
|
130
|
-
# start listening on promise's notification
|
131
|
-
raw_conn.exec("LISTEN promise_#{id}")
|
132
|
-
|
133
|
-
last = latest
|
134
|
-
|
135
|
-
# if job hasn't started yet, wait for it to start
|
136
|
-
if !last.start_dt
|
137
|
-
# log "AAAA #{Process.pid} #{last}"
|
138
|
-
|
139
|
-
job = Delayed::Job.find_by_id(last.job_id)
|
140
|
-
job.reload if job # paranoid
|
141
|
-
|
142
|
-
if !job && job.locked_at
|
143
|
-
# job has been locked, so it looks like it started already
|
144
|
-
# and we need to wait for it.
|
145
|
-
wait_for_my_notify(Marty::Promise::DEFAULT_JOB_TIMEOUT)
|
146
|
-
else
|
147
|
-
# work off the job instead of waiting for a real worker to
|
148
|
-
# pick it up.
|
149
|
-
# log "OFF0 #{Process.pid} #{last}"
|
150
|
-
begin
|
151
|
-
work_off_job(job)
|
152
|
-
rescue => exc
|
153
|
-
# log "OFFERR #{exc}"
|
154
|
-
res = Delorean::Engine.grok_runtime_exception(exc)
|
155
|
-
last.set_result(res)
|
156
|
-
end
|
157
|
-
# log "OFF1 #{Process.pid} #{last}"
|
158
|
-
end
|
159
|
-
|
160
|
-
last = latest
|
161
|
-
|
162
|
-
# we waited for it but it never started. So, mark it with a
|
163
|
-
# timeout error.
|
164
|
-
if !last.start_dt
|
165
|
-
# log "TO11 #{Process.pid} #{last}"
|
166
|
-
return {"error" => "promise #{last.id} timed out (never started)"}
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
# reload promise in case out copy doesn't have a result yet
|
171
|
-
last = latest unless last.end_dt
|
172
|
-
|
173
|
-
# at this point, we know the promise has already started
|
174
|
-
if !last.end_dt
|
175
|
-
wait_for_my_notify(timeout)
|
176
|
-
# log "UUUU #{Process.pid} #{id} #{Time.now.to_f}"
|
177
|
-
last = latest
|
178
|
-
|
179
|
-
# log "XXXX #{Process.pid} #{Time.now.to_f} #{last}"
|
180
|
-
|
181
|
-
if !last.end_dt
|
182
|
-
# log "TO22 #{Process.pid} #{last}"
|
183
|
-
return {"error" => "promise #{last.id} timed out (didn't end)"}
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# log "RRRR #{Process.pid} #{last} #{Time.now.to_f}"
|
188
|
-
|
189
|
-
last.result
|
190
|
-
ensure
|
191
|
-
# Stop listening to the promise notifications
|
192
|
-
raw_conn.exec("UNLISTEN promise_#{id}")
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
196
|
-
end
|