inst_data_shipper 0.1.0.beta2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +139 -1
- data/db/migrate/20240301090836_create_inst_data_shipper_dump_batches.rb +3 -2
- data/lib/inst_data_shipper/basic_dumper.rb +1 -1
- data/lib/inst_data_shipper/data_sources/local_tables.rb +9 -2
- data/lib/inst_data_shipper/destinations/base.rb +6 -2
- data/lib/inst_data_shipper/destinations/hosted_data.rb +35 -2
- data/lib/inst_data_shipper/dumper.rb +38 -11
- data/lib/inst_data_shipper/schema_builder.rb +15 -5
- data/lib/inst_data_shipper/version.rb +1 -1
- data/lib/inst_data_shipper.rb +2 -1
- metadata +4 -5
- data/lib/inst_data_shipper/jobs/basic_dump_job.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7909aa44e9dabd1d43d58a5a3c2c081891104d64336294dce287c06804804df
|
4
|
+
data.tar.gz: 5da874689ac1de3e016a7feefce5866b211e6f7595021b565564f796685ed104
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd81e6c26e2416ce1a32de588e04f560496cfb7cfdac3f4c837828a1c65798bec405d98197032b0d8935a1ba2b24a291aa25f1b73a469ac7a9c6ef8d2286103f
|
7
|
+
data.tar.gz: 66c5ccfd82128e8c5dc39c7c937ee7f4f9412743b7202e221e53c575d4b0e572f0b014b4f41ae5924b1d2d119a05cd5de2acbae4eb81022df844a1fea181faec
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# InstDataShipper
|
2
2
|
|
3
|
-
This gem is intended to facilitate
|
3
|
+
This gem is intended to facilitate easy upload of LTI datasets to Instructure Hosted Data.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -16,6 +16,144 @@ Then run the migrations:
|
|
16
16
|
bundle exec rake db:migrate
|
17
17
|
```
|
18
18
|
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Dumper
|
22
|
+
|
23
|
+
The main tool provided by this Gem is the `InstDataDumper::Dumper` class. It is used to define a "Dump" which is a combination of tasks and schema.
|
24
|
+
|
25
|
+
Here is an example `Dumper` implementation, wrapped in an ActiveJob job:
|
26
|
+
```ruby
|
27
|
+
class HostedDataPushJob < ApplicationJob
|
28
|
+
# The schema serves two purposes: defining the schema and mapping data
|
29
|
+
SCHEMA = InstDataShipper::SchemaBuilder.build do
|
30
|
+
# You can augment the Table-builder DSL with custom methods like so:
|
31
|
+
extend_table_builder do
|
32
|
+
# It may be useful to define a custom column definition helpers:
|
33
|
+
def custom_column(*args, from: nil, **kwargs, &blk)
|
34
|
+
# In this example, the helper reads the value from a `data` jsonb column - without it, you'd need
|
35
|
+
# to define `from: ->(row) { row.data["<KEY>"] }` on each column that needs to read from the jsonb
|
36
|
+
from ||= args[0].to_s
|
37
|
+
from = ->(row) { row.data[from] } if from.is_a?(String)
|
38
|
+
column(*args, **kwargs, from: from, &blk)
|
39
|
+
end
|
40
|
+
|
41
|
+
# `extend_table_builder` uses `class_eval`, so you could alternatively write your helpers in a Concern or Module and include them like normal:
|
42
|
+
include SomeConcern
|
43
|
+
end
|
44
|
+
|
45
|
+
table(ALocalModel, "<TABLE DESCRIPTION>") do
|
46
|
+
# If you define a table as incremental, it'll only export changes made since the start of the last successful Dumper run
|
47
|
+
# The first argument "scope" can be interpreted in different ways:
|
48
|
+
# If exporting a local model it may be a: (default: `updated_at`)
|
49
|
+
# Proc that will receive a Relation and return a Relation (use `incremental_since`)
|
50
|
+
# String of a column to compare with `incremental_since`
|
51
|
+
# If exporting a Canvas report it may be a: (default: `updated_after`)
|
52
|
+
# Proc that will receive report params and return modified report params (use `incremental_since`)
|
53
|
+
# String of a report param to set to `incremental_since`
|
54
|
+
# `on:` is passed to Hosted Data and is used as the unique key. It may be an array to form a composite-key
|
55
|
+
# `if:` may be a Proc or a Symbol (of a method on the Dumper)
|
56
|
+
incremental "updated_at", on: [:id], if: ->() {}
|
57
|
+
|
58
|
+
column :name_in_destinations, :maybe_optional_sql_type, "Optional description of column"
|
59
|
+
|
60
|
+
# The type may usually be omitted if the `table()` is passed a Model class, but strings are an exception to this
|
61
|
+
custom_column :name, :"varchar(128)"
|
62
|
+
|
63
|
+
# `from:` May be...
|
64
|
+
# A Symbol of a method to be called on the record
|
65
|
+
custom_column :sis_type, :"varchar(32)", from: :some_model_method
|
66
|
+
# A String of a column to read from the record
|
67
|
+
custom_column :sis_type, :"varchar(32)", from: "sis_source_type"
|
68
|
+
# A Proc to be called with each record
|
69
|
+
custom_column :sis_type, :"varchar(32)", from: ->(rec) { ... }
|
70
|
+
# Not specified. Will default to using the Schema Column Name as a String ("sis_type" in this case)
|
71
|
+
custom_column :sis_type, :"varchar(32)"
|
72
|
+
end
|
73
|
+
|
74
|
+
table("my_table", model: ALocalModel) do
|
75
|
+
# ...
|
76
|
+
end
|
77
|
+
|
78
|
+
table("proserv_student_submissions_csv") do
|
79
|
+
column :canvas_id, :bigint, from: "canvas user id"
|
80
|
+
column :sis_id, :"varchar(64)", from: "sis user id"
|
81
|
+
column :name, :"varchar(64)", from: "user name"
|
82
|
+
column :submission_id, :bigint, from: "submission id"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
Dumper = InstDataShipper::Dumper.define(schema: SCHEMA, include: [
|
87
|
+
InstDataShipper::DataSources::LocalTables,
|
88
|
+
InstDataShipper::DataSources::CanvasReports,
|
89
|
+
]) do
|
90
|
+
import_local_table(ALocalModel)
|
91
|
+
import_canvas_report_by_terms("proserv_student_submissions_csv", terms: Term.all.pluck(:canvas_id))
|
92
|
+
|
93
|
+
# If the report_name/Model don't directly match the Schema, a schema_name: parameter may be passed:
|
94
|
+
import_local_table(SomeModel, schema_name: "my_table")
|
95
|
+
import_canvas_report_by_terms("some_report", terms: Term.all.pluck(:canvas_id), schema_name: "my_table")
|
96
|
+
end
|
97
|
+
|
98
|
+
def perform
|
99
|
+
Dumper.perform_dump([
|
100
|
+
"hosted-data://<JWT>@<HOSTED DATA SERVER>?table_prefix=example",
|
101
|
+
"s3://<access_key_id>:<access_key_secret>@<region>/<bucket>/<path>",
|
102
|
+
])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
`Dumper`s may also be formed as a normal Ruby subclass:
|
108
|
+
```ruby
|
109
|
+
class HostedDataPushJob < ApplicationJob
|
110
|
+
SCHEMA = InstDataShipper::SchemaBuilder.build do
|
111
|
+
# ...
|
112
|
+
end
|
113
|
+
|
114
|
+
class Dumper < InstDataShipper::Dumper
|
115
|
+
include InstDataShipper::DataSources::LocalTables
|
116
|
+
include InstDataShipper::DataSources::CanvasReports
|
117
|
+
|
118
|
+
def enqueue_tasks
|
119
|
+
import_local_table(ALocalModel)
|
120
|
+
import_canvas_report_by_terms("proserv_student_submissions_csv", terms: Term.all.pluck(:canvas_id))
|
121
|
+
end
|
122
|
+
|
123
|
+
def table_schemas
|
124
|
+
SCHEMA
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def perform
|
129
|
+
Dumper.perform_dump([
|
130
|
+
"hosted-data://<JWT>@<HOSTED DATA SERVER>?table_prefix=example",
|
131
|
+
"s3://<access_key_id>:<access_key_secret>@<region>/<bucket>/<path>",
|
132
|
+
])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
### Destinations
|
138
|
+
|
139
|
+
This Gem is mainly designed for use with Hosted Data, but it tries to abstract that a little to allow for other destinations/backends. Out of the box, support for Hosted Data and S3 are included.
|
140
|
+
|
141
|
+
Destinations are passed as URI-formatted strings. Passing Hashes is also supported, but the format/keys are destination specific.
|
142
|
+
|
143
|
+
Destinations blindly accept URI Fragments (the `#` chunk at the end of the URI). These options are not used internally but will be made available as `dest.user_config`. Ideally these are in the same format as query parameters (`x=1&y=2`, which it will try to parse into a Hash), but it can be any string.
|
144
|
+
|
145
|
+
#### Hosted Data
|
146
|
+
`hosted-data://<JWT>@<HOSTED DATA SERVER>`
|
147
|
+
|
148
|
+
##### Optional Parameters:
|
149
|
+
- `table_prefix`: An optional string to prefix onto each table name in the schema when declaring the schema in Hosted Data
|
150
|
+
|
151
|
+
#### S3
|
152
|
+
`s3://<access_key_id>:<access_key_secret>@<region>/<bucket>/<optional path>`
|
153
|
+
|
154
|
+
##### Optional Parameters:
|
155
|
+
_None_
|
156
|
+
|
19
157
|
## Development
|
20
158
|
|
21
159
|
When adding to or updating this gem, make sure you do the following:
|
@@ -7,11 +7,12 @@ class CreateInstDataShipperDumpBatches < CanvasSync::MiscHelper::MigrationClass
|
|
7
7
|
|
8
8
|
t.string :job_class
|
9
9
|
t.string :genre
|
10
|
+
t.string :batch_id
|
10
11
|
|
11
12
|
t.string :exception
|
12
13
|
t.text :backtrace
|
13
|
-
t.text :metadata
|
14
|
-
t.text :job_arguments
|
14
|
+
# t.text :metadata
|
15
|
+
# t.text :job_arguments
|
15
16
|
|
16
17
|
t.timestamps
|
17
18
|
end
|
@@ -22,7 +22,12 @@ module InstDataShipper
|
|
22
22
|
query = _resolve_model_query(query, table_def[:query])
|
23
23
|
|
24
24
|
if table_is_incremental?(table_def)
|
25
|
-
query = _resolve_model_query(
|
25
|
+
query = _resolve_model_query(
|
26
|
+
query,
|
27
|
+
table_def.dig(:incremental, :scope),
|
28
|
+
string: ->(query, column) { query.where("#{column} > ?", incremental_since) },
|
29
|
+
default: "updated_at",
|
30
|
+
)
|
26
31
|
end
|
27
32
|
|
28
33
|
query.find_each do |m|
|
@@ -35,7 +40,9 @@ module InstDataShipper
|
|
35
40
|
upload_data(table_def, &inner_block)
|
36
41
|
end
|
37
42
|
|
38
|
-
def _resolve_model_query(relation, query, string: nil)
|
43
|
+
def _resolve_model_query(relation, query, string: nil, default: nil)
|
44
|
+
return relation if query == false
|
45
|
+
query = default if query.nil?
|
39
46
|
return relation if query.nil?
|
40
47
|
|
41
48
|
if query.is_a?(Symbol)
|
@@ -3,7 +3,7 @@ module InstDataShipper
|
|
3
3
|
class Base
|
4
4
|
attr_reader :dumper
|
5
5
|
|
6
|
-
delegate :tracker, :
|
6
|
+
delegate :tracker, :schema, :working_dir, to: :dumper
|
7
7
|
|
8
8
|
def initialize(cache_key, config, dumper)
|
9
9
|
@cache_key = cache_key
|
@@ -11,9 +11,13 @@ module InstDataShipper
|
|
11
11
|
@dumper = dumper
|
12
12
|
end
|
13
13
|
|
14
|
+
# This method is called before taking any actions.
|
15
|
+
# It should be used to make any necessarry state assumptions (eg, the HostedData destination checks for a previous dump to determine if it can use incremental_since)
|
16
|
+
def preinitialize_dump(context); end
|
17
|
+
|
14
18
|
# This method is called before processing any data.
|
15
19
|
# It should be used to initialize any external resources needed for the dump.
|
16
|
-
def initialize_dump; end
|
20
|
+
def initialize_dump(context); end
|
17
21
|
|
18
22
|
# Yields an object (can be anything) that will be passed to `upload_data_chunk` as `chunk`.
|
19
23
|
#
|
@@ -5,11 +5,43 @@ module InstDataShipper
|
|
5
5
|
class HostedData < Base
|
6
6
|
include Concerns::Chunking
|
7
7
|
|
8
|
-
def
|
8
|
+
def preinitialize_dump(context)
|
9
|
+
if context[:incremental_since].present?
|
10
|
+
begin
|
11
|
+
last_dump = hosted_data_client.get("api/v1/custom_dumps/last", {
|
12
|
+
status: 'imported',
|
13
|
+
# schema_version: convert_schema[:version],
|
14
|
+
tags: [
|
15
|
+
"ids-schema=#{dumper.schema_digest}",
|
16
|
+
"ids-genre=#{dumper.export_genre}",
|
17
|
+
],
|
18
|
+
}).body.with_indifferent_access
|
19
|
+
|
20
|
+
if last_dump[:created_at] < context[:incremental_since]
|
21
|
+
InstDataShipper.logger.info("Last successful HostedData dump is older than incremental_since - bumping back incremental_since")
|
22
|
+
context[:incremental_since] = last_dump[:created_at]
|
23
|
+
end
|
24
|
+
rescue Faraday::ResourceNotFound
|
25
|
+
# TODO It'd be nice to make this per-table
|
26
|
+
InstDataShipper.logger.info("No Last successful HostedData dump of the same schema - not using incremental_since")
|
27
|
+
context[:incremental_since] = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize_dump(context)
|
33
|
+
tags = [
|
34
|
+
"ids-schema=#{dumper.schema_digest}",
|
35
|
+
"ids-genre=#{dumper.export_genre}",
|
36
|
+
]
|
37
|
+
tags << "ids-app=#{Rails.application.class.name.gsub(/::Application$/, '')}" if defined?(Rails) && Rails.application
|
38
|
+
tags << "ids-schema-version=#{schema[:version]}" if schema[:version].present?
|
39
|
+
|
9
40
|
dump = hosted_data_client.post(
|
10
41
|
'api/v1/custom_dumps/',
|
11
42
|
reference_id: tracker.id,
|
12
43
|
schema: convert_schema,
|
44
|
+
tags: tags,
|
13
45
|
).body.with_indifferent_access
|
14
46
|
|
15
47
|
redis.hset(rk(:state), :dump_id, dump[:id])
|
@@ -62,6 +94,7 @@ module InstDataShipper
|
|
62
94
|
|
63
95
|
def convert_schema
|
64
96
|
definititions = {}
|
97
|
+
table_schemas = schema[:tables]
|
65
98
|
table_schemas.each do |ts|
|
66
99
|
ts = ts.dup
|
67
100
|
tname = table_name(ts)
|
@@ -86,7 +119,7 @@ module InstDataShipper
|
|
86
119
|
end
|
87
120
|
|
88
121
|
{
|
89
|
-
version: "#{dumper.
|
122
|
+
version: "#{dumper.schema_digest}-#{Digest::MD5.hexdigest(definititions.to_json)[0...6]}",
|
90
123
|
definition: definititions,
|
91
124
|
}
|
92
125
|
end
|
@@ -19,10 +19,20 @@ module InstDataShipper
|
|
19
19
|
include(*include)
|
20
20
|
|
21
21
|
define_method(:enqueue_tasks, &blk)
|
22
|
-
define_method(:
|
22
|
+
define_method(:schema) { schema }
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def self.current(executor: nil)
|
27
|
+
cur_batch = Thread.current[CanvasSync::JobBatches::CURRENT_BATCH_THREAD_KEY]
|
28
|
+
ctx = cur_batch&.context || {}
|
29
|
+
return nil unless ctx[:origin_class].present? && ctx[:tracker_id].present?
|
30
|
+
|
31
|
+
clazz = ctx[:origin_class]
|
32
|
+
clazz = clazz.constantize if clazz.is_a?(String)
|
33
|
+
clazz.new(executor: executor)
|
34
|
+
end
|
35
|
+
|
26
36
|
public
|
27
37
|
|
28
38
|
def begin_dump
|
@@ -31,15 +41,18 @@ module InstDataShipper
|
|
31
41
|
@tracker = tracker = DumpBatch.create(job_class: self.class.to_s, genre: export_genre, status: 'in_progress')
|
32
42
|
|
33
43
|
@batch_context = context = {
|
34
|
-
# TODO Allow to be hooked by Destination, likely via initialize_dump_batch and batch_context, so that if an earlier destination fails we can resend data
|
35
44
|
# TODO Consider behavior if last is still running
|
36
|
-
incremental_since:
|
45
|
+
incremental_since: last_successful_tracker&.created_at,
|
37
46
|
}
|
38
47
|
|
48
|
+
destinations.each do |dest|
|
49
|
+
dest.preinitialize_dump(context)
|
50
|
+
end
|
51
|
+
|
39
52
|
begin
|
40
53
|
begin
|
41
54
|
destinations.each do |dest|
|
42
|
-
dest.initialize_dump()
|
55
|
+
dest.initialize_dump(context)
|
43
56
|
end
|
44
57
|
|
45
58
|
run_hook(:initialize_dump_batch, context)
|
@@ -52,6 +65,7 @@ module InstDataShipper
|
|
52
65
|
|
53
66
|
Sidekiq::Batch.new.tap do |batch|
|
54
67
|
context[:root_bid] = batch.bid
|
68
|
+
tracker.update(batch_id: batch.bid)
|
55
69
|
|
56
70
|
batch.description = "HD #{export_genre} Export #{tracker.id} Root"
|
57
71
|
batch.context = context
|
@@ -62,6 +76,7 @@ module InstDataShipper
|
|
62
76
|
rescue => ex
|
63
77
|
delayed :cleanup_fatal_error!
|
64
78
|
InstDataShipper.handle_suppressed_error(ex)
|
79
|
+
tracker.update(status: 'failed', exception: ex.message, backtrace: ex.backtrace.join("\n"))
|
65
80
|
end
|
66
81
|
end
|
67
82
|
rescue => ex
|
@@ -74,6 +89,7 @@ module InstDataShipper
|
|
74
89
|
end
|
75
90
|
end
|
76
91
|
end
|
92
|
+
tracker.update(status: 'failed', exception: ex.message, backtrace: ex.backtrace.join("\n"))
|
77
93
|
raise ex
|
78
94
|
end
|
79
95
|
end
|
@@ -82,15 +98,31 @@ module InstDataShipper
|
|
82
98
|
@tracker ||= batch_context[:tracker_id].present? ? DumpBatch.find(batch_context[:tracker_id]) : nil
|
83
99
|
end
|
84
100
|
|
101
|
+
def last_successful_tracker
|
102
|
+
@last_successful_tracker ||= DumpBatch.where(job_class: self.class.to_s, genre: export_genre, status: 'completed').order(created_at: :desc).first
|
103
|
+
end
|
104
|
+
|
85
105
|
def export_genre
|
86
|
-
self.class.to_s
|
106
|
+
self.class.to_s
|
87
107
|
end
|
88
108
|
|
89
109
|
def origin_class
|
90
110
|
batch_context[:origin_class]&.constantize || self.class
|
91
111
|
end
|
92
112
|
|
113
|
+
def schema
|
114
|
+
return origin_class::SCHEMA if defined?(origin_class::SCHEMA)
|
115
|
+
raise NotImplementedError
|
116
|
+
end
|
117
|
+
|
118
|
+
def schema_digest
|
119
|
+
Digest::MD5.hexdigest(schema.to_json)[0...8]
|
120
|
+
end
|
121
|
+
|
93
122
|
def table_is_incremental?(table_def)
|
123
|
+
return false unless incremental_since.present?
|
124
|
+
|
125
|
+
# TODO Return false if table's schema changes
|
94
126
|
if (inc = table_def[:incremental]).present?
|
95
127
|
differ = inc[:if]
|
96
128
|
return !!incremental_since if differ.nil?
|
@@ -119,7 +151,7 @@ module InstDataShipper
|
|
119
151
|
|
120
152
|
value = Array(value).compact
|
121
153
|
|
122
|
-
|
154
|
+
schema[:tables].each do |ts|
|
123
155
|
return ts if value.include?(ts[key])
|
124
156
|
end
|
125
157
|
end
|
@@ -207,11 +239,6 @@ module InstDataShipper
|
|
207
239
|
|
208
240
|
# Helper Methods
|
209
241
|
|
210
|
-
def table_schemas
|
211
|
-
return origin_class::TABLE_SCHEMAS if defined?(origin_class::TABLE_SCHEMAS)
|
212
|
-
raise NotImplementedError
|
213
|
-
end
|
214
|
-
|
215
242
|
def delayed(mthd, *args, **kwargs)
|
216
243
|
Jobs::AsyncCaller.perform_later(self.class.to_s, mthd.to_s, *args, **kwargs)
|
217
244
|
end
|
@@ -2,16 +2,22 @@ module InstDataShipper
|
|
2
2
|
# This class ends up fill two roles - Schema and Mapping.
|
3
3
|
# It makes for a clean API, but it's a little less canonical since, (eg) the S3 destination doesn't need column type annotations.
|
4
4
|
class SchemaBuilder
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :schema
|
6
6
|
|
7
7
|
def initialize
|
8
|
-
@
|
8
|
+
@schema = {
|
9
|
+
tables: [],
|
10
|
+
}
|
9
11
|
end
|
10
12
|
|
11
13
|
def self.build(&block)
|
12
14
|
builder = new
|
13
15
|
builder.instance_exec(&block)
|
14
|
-
builder.
|
16
|
+
builder.schema
|
17
|
+
end
|
18
|
+
|
19
|
+
def version(version)
|
20
|
+
@schema[:version] = version
|
15
21
|
end
|
16
22
|
|
17
23
|
def extend_table_builder(&block)
|
@@ -45,7 +51,7 @@ module InstDataShipper
|
|
45
51
|
|
46
52
|
@table_builder_class.build(tdef, &block)
|
47
53
|
|
48
|
-
@tables << tdef
|
54
|
+
@schema[:tables] << tdef
|
49
55
|
|
50
56
|
tdef
|
51
57
|
end
|
@@ -68,7 +74,11 @@ module InstDataShipper
|
|
68
74
|
# options[key] = value
|
69
75
|
# end
|
70
76
|
|
71
|
-
def
|
77
|
+
def version(version)
|
78
|
+
options[:version] = version
|
79
|
+
end
|
80
|
+
|
81
|
+
def incremental(scope=nil, **kwargs)
|
72
82
|
if (extras = kwargs.keys - %i[on if]).present?
|
73
83
|
raise ArgumentError, "Unsuppored options: #{extras.inspect}"
|
74
84
|
end
|
data/lib/inst_data_shipper.rb
CHANGED
@@ -39,6 +39,7 @@ module InstDataShipper
|
|
39
39
|
|
40
40
|
def logger
|
41
41
|
return @logger if defined? @logger
|
42
|
+
# TODO Annotate logs with DumpBatch ID
|
42
43
|
@logger = Logger.new(STDOUT)
|
43
44
|
@logger.level = Logger::DEBUG
|
44
45
|
@logger
|
@@ -49,7 +50,7 @@ module InstDataShipper
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def redis_prefix
|
52
|
-
pfx = "
|
53
|
+
pfx = "ids"
|
53
54
|
pfx = "#{Apartment::Tenant.current}:#{pfx}" if defined?(Apartment)
|
54
55
|
pfx
|
55
56
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inst_data_shipper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Instructure CustomDev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -399,7 +399,6 @@ files:
|
|
399
399
|
- lib/inst_data_shipper/engine.rb
|
400
400
|
- lib/inst_data_shipper/jobs/async_caller.rb
|
401
401
|
- lib/inst_data_shipper/jobs/base.rb
|
402
|
-
- lib/inst_data_shipper/jobs/basic_dump_job.rb
|
403
402
|
- lib/inst_data_shipper/record.rb
|
404
403
|
- lib/inst_data_shipper/schema_builder.rb
|
405
404
|
- lib/inst_data_shipper/version.rb
|
@@ -436,9 +435,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
436
435
|
version: '0'
|
437
436
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
438
437
|
requirements:
|
439
|
-
- - "
|
438
|
+
- - ">="
|
440
439
|
- !ruby/object:Gem::Version
|
441
|
-
version:
|
440
|
+
version: '0'
|
442
441
|
requirements: []
|
443
442
|
rubygems_version: 3.1.6
|
444
443
|
signing_key:
|