asyncapi-server 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +39 -2
  4. data/app/controllers/asyncapi/server/v1/jobs_controller.rb +2 -1
  5. data/app/serializers/asyncapi/server/job_serializer.rb +1 -1
  6. data/app/workers/asyncapi/server/job_status_notifier_worker.rb +51 -0
  7. data/app/workers/asyncapi/server/job_worker.rb +16 -18
  8. data/db/migrate/20141112034324_create_asyncapi_server_jobs.rb +1 -1
  9. data/db/migrate/20141212064931_add_secret_to_asyncapi_server_job.rb +1 -1
  10. data/db/migrate/20150130062520_add_expired_at_to_asyncapi_server_job.rb +1 -1
  11. data/db/migrate/20150201231018_drop_expired_at_from_asyncapi_server_jobs.rb +1 -1
  12. data/lib/asyncapi/server.rb +3 -0
  13. data/lib/asyncapi/server/rails_ext/controller.rb +3 -1
  14. data/lib/asyncapi/server/rspec.rb +20 -7
  15. data/lib/asyncapi/server/version.rb +1 -1
  16. data/spec/controllers/asyncapi/server/v1/jobs_controller_spec.rb +4 -4
  17. data/spec/dummy/db/development.sqlite3 +0 -0
  18. data/spec/dummy/db/schema.rb +2 -2
  19. data/spec/dummy/db/test.sqlite3 +0 -0
  20. data/spec/dummy/log/development.log +81 -0
  21. data/spec/dummy/log/test.log +2011 -0
  22. data/spec/models/job_spec.rb +1 -1
  23. data/spec/requests/enqueueing_jobs_spec.rb +10 -19
  24. data/spec/serializers/job_serializer_spec.rb +1 -0
  25. data/spec/spec_helper.rb +5 -4
  26. data/spec/workers/job_status_notifier_worker_spec.rb +115 -0
  27. data/spec/workers/job_worker_spec.rb +9 -30
  28. metadata +91 -47
  29. data/spec/dummy/db/migrate/20141212065005_create_asyncapi_server_jobs.asyncapi_server.rb +0 -11
  30. data/spec/dummy/db/migrate/20141212065006_add_secret_to_asyncapi_server_job.asyncapi_server.rb +0 -6
  31. data/spec/dummy/db/migrate/20150130062901_add_expired_at_to_asyncapi_server_job.asyncapi_server.rb +0 -12
  32. data/spec/dummy/db/migrate/20150201231329_drop_expired_at_from_asyncapi_server_jobs.asyncapi_server.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2cd757bb2567503b5ba9d8ce6e83ca056a199305
4
- data.tar.gz: 57cf7ac80d344addd357356b8949e3fdd3bc4fae
2
+ SHA256:
3
+ metadata.gz: d20ce991b75b2d975140fb6ec3d1a9dffb14116167bbcd072007ad7d3b15b9af
4
+ data.tar.gz: e64c1c4061e6b85b320258d995636a402858f96dfe5b66e59b32541296f798c9
5
5
  SHA512:
6
- metadata.gz: 4e9f48b45f660abbed76f254fd0c93ed330c071c816c38f2a0ff7c761ab0110498837594fee02408bc8d906a128478861dbdde68933bd33512c623242fe265dc
7
- data.tar.gz: c0292eab80325a33914f37997f7d7bf79a175c3090ab5f8c2ae7881e86d3315d8bcfe57b71343ad9115ff583b2b08e6e653ed39e5987f767971f1a0cfc262272
6
+ metadata.gz: 77bfca4c01e794d67678f942d89df08afa0f82f8c2b84ae08806e2e00f3cf3cdd67e02f36166952eddc5d6fbeb279fd36659d1df7f43e126713e020f7dbefe1d
7
+ data.tar.gz: 9ef0745fcf8bcd1922f1bd997c6470b2ae05ab1f072e6a8f73e4b4df3d6f906394a2d9c5b464e016b2589370d2f7b3ab536ef2979f0bba3a4fbc5cf1993ac4ff
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2015 G5
1
+ Copyright 2016 G5
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -54,6 +54,37 @@ If you use `protected_attributes`, in an initializer:
54
54
  Asyncapi::Server::Job.attr_accessible :status, :callback_url, :class_name, :params, :secret
55
55
  ```
56
56
 
57
+ ## Usage without Asyncapi::Client
58
+
59
+ If you want to use this without asyncapi client, you need to prepare two things: the endpoint that asyncapi-server will reply to.
60
+
61
+ Create the job by POSTing the following to CreateSomething above:
62
+
63
+ ```json
64
+ {
65
+ "job": {
66
+ "callback_url": "https://myclient.com/jobs_callback",
67
+ "params": {
68
+ "name": "Something's name",
69
+ "approved": true
70
+ },
71
+ "secret": "A secret unique to this job, so that you know what job the server is referring to"
72
+ }
73
+ }
74
+ ```
75
+
76
+ When the server is done processing, it will post something to your client. Your endpoint must accept the following json as the body:
77
+
78
+ ```
79
+ {
80
+ "job": {
81
+ "status": "success",
82
+ "message": "The output of the Runner class (i.e. `CreateSomething`)",
83
+ "secret": "The secret you had sent earlier (this is how you can be sure it's not someone else updating your endpoint)",
84
+ }
85
+ }
86
+ ```
87
+
57
88
  ### RSpec
58
89
 
59
90
  If you want to create an integration spec for you Asyncapi server endpoint, make sure you require the helper:
@@ -65,14 +96,20 @@ require "asyncapi/server/rspec"
65
96
  When you make a request, instead of `post`, use `asyncapi_post`. Ex:
66
97
 
67
98
  ```ruby
68
- asyncapi_post("/api/v1/long_running_job", name: "Compute")
99
+ asyncapi_post("/api/v1/long_running_job", params: { name: "Compute" })
69
100
  ```
70
101
 
71
102
  This helper calls `post` underneath but builds the request in a way that Asyncapi server understands.
72
103
 
104
+ ## Development
105
+
106
+ - Run `rake db:migrate && rake db:migrate RAILS_ENV=test`
107
+ - Make changes
108
+ - `rspec`
109
+
73
110
  ## License
74
111
 
75
- Copyright (c) 2015 G5
112
+ Copyright (c) 2016 G5
76
113
 
77
114
  MIT License
78
115
 
@@ -2,6 +2,7 @@ module Asyncapi
2
2
  module Server
3
3
  module V1
4
4
  class JobsController < ApplicationController # TODO: Asyncapi::Server.parent_controller
5
+ include Rails::Pagination
5
6
 
6
7
  protect_from_forgery with: :null_session
7
8
  respond_to :json
@@ -24,7 +25,7 @@ module Asyncapi
24
25
  job.destroy
25
26
  respond_with job
26
27
  else
27
- render nothing: true, status: 404
28
+ head :not_found
28
29
  end
29
30
  end
30
31
 
@@ -2,7 +2,7 @@ module Asyncapi
2
2
  module Server
3
3
  class JobSerializer < ActiveModel::Serializer
4
4
 
5
- attributes :id, :url, :secret
5
+ attributes :id, :status, :url, :secret
6
6
 
7
7
  end
8
8
  end
@@ -0,0 +1,51 @@
1
+ module Asyncapi::Server
2
+ class JobStatusNotifierWorker
3
+
4
+ include Sidekiq::Worker
5
+ sidekiq_options retry: false
6
+ MAX_RETRIES = 2
7
+
8
+ def perform(job_id, job_message, retries=0)
9
+ @job = Job.find(job_id)
10
+
11
+ report_job_status(job_message)
12
+
13
+ unless @response.code == 200
14
+ if retries <= MAX_RETRIES
15
+ @jid = JobStatusNotifierWorker.perform_async(job_id, job_message, retries+1)
16
+ else
17
+ raise format_error("Something went wrong while poking #{@job.callback_url}")
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def report_job_status(job_message)
25
+ @response ||= Typhoeus.put(
26
+ @job.callback_url,
27
+ body: {
28
+ job: {
29
+ status: @job.status,
30
+ message: @job_message,
31
+ secret: @job.secret,
32
+ }
33
+ }.to_json,
34
+ headers: {
35
+ "Content-Type" => "application/json",
36
+ Accept: "application/json"
37
+ }
38
+ )
39
+ end
40
+
41
+ def format_error(error)
42
+ [
43
+ error,
44
+ "JobID: #{@job.id}",
45
+ "Next Attempt: #{@jid}",
46
+ "HTTP Status: #{@response.code}",
47
+ "HTTP Response: #{@response.inspect}",
48
+ ].join("\n")
49
+ end
50
+ end
51
+ end
@@ -3,8 +3,9 @@ module Asyncapi::Server
3
3
 
4
4
  include Sidekiq::Worker
5
5
  sidekiq_options retry: false
6
+ MAX_RETRIES = 2
6
7
 
7
- def perform(job_id)
8
+ def perform(job_id, retries=0)
8
9
  job = Job.find(job_id)
9
10
  runner_class = job.class_name.constantize
10
11
 
@@ -15,28 +16,25 @@ module Asyncapi::Server
15
16
  job_message = [e.message, e.backtrace].flatten.join("\n")
16
17
  raise e
17
18
  ensure
18
- job.update_attributes(status: job_status)
19
- report_job_status(job, job_message)
19
+ if job
20
+ job.update_attributes(status: job_status)
21
+ report_job_status(job, job_message)
22
+ else
23
+ # For some reason "ActiveRecord::Base.after_transaction",
24
+ # ":after_commit" and ":after_create" does not prevent
25
+ # the ActiveRecord-Sidekiq race condition. In order to
26
+ # prevent this just retry running JobWorker until it finds
27
+ # the job by job_id.
28
+ if retries <= MAX_RETRIES
29
+ JobWorker.perform_async(job_id, retries+1)
30
+ end
31
+ end
20
32
  end
21
33
 
22
34
  private
23
35
 
24
36
  def report_job_status(job, job_message)
25
- Typhoeus.put(
26
- job.callback_url,
27
- body: {
28
- job: {
29
- status: job.status,
30
- message: job_message,
31
- secret: job.secret,
32
- }
33
- }.to_json,
34
- headers: {
35
- "Content-Type" => "application/json",
36
- Accept: "application/json"
37
- }
38
- )
37
+ JobStatusNotifierWorker.perform_async(job.id, job_message)
39
38
  end
40
-
41
39
  end
42
40
  end
@@ -1,4 +1,4 @@
1
- class CreateAsyncapiServerJobs < ActiveRecord::Migration
1
+ class CreateAsyncapiServerJobs < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  create_table :asyncapi_server_jobs do |t|
4
4
  t.integer :status
@@ -1,4 +1,4 @@
1
- class AddSecretToAsyncapiServerJob < ActiveRecord::Migration
1
+ class AddSecretToAsyncapiServerJob < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_server_jobs, :secret, :string
4
4
  end
@@ -1,4 +1,4 @@
1
- class AddExpiredAtToAsyncapiServerJob < ActiveRecord::Migration
1
+ class AddExpiredAtToAsyncapiServerJob < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_server_jobs, :expired_at, :datetime
4
4
 
@@ -1,4 +1,4 @@
1
- class DropExpiredAtFromAsyncapiServerJobs < ActiveRecord::Migration
1
+ class DropExpiredAtFromAsyncapiServerJobs < ActiveRecord::Migration[4.2]
2
2
  def up
3
3
  remove_column :asyncapi_server_jobs, :expired_at
4
4
  end
@@ -1,3 +1,6 @@
1
+ require 'active_model_serializers'
2
+ require 'responders'
3
+ require 'ar_after_transaction'
1
4
  require "asyncapi/server/engine"
2
5
 
3
6
  module Asyncapi
@@ -9,8 +9,10 @@ module Asyncapi
9
9
  def async(method_name, klass)
10
10
  define_method(method_name) do
11
11
  job = Job.create(job_params_with(klass.name))
12
+ ActiveRecord::Base.after_transaction do
13
+ JobWorker.perform_async(job.id)
14
+ end
12
15
  serializer = JobSerializer.new(job)
13
- JobWorker.perform_async(job.id)
14
16
  render json: serializer
15
17
  end
16
18
  end
@@ -3,15 +3,28 @@ module Asyncapi
3
3
  module RSpec
4
4
 
5
5
  def asyncapi_post(url, params)
6
- post(url, {
7
- job: {
8
- callback_url: "callback_url",
9
- params: params,
10
- secret: "sekret",
11
- }
12
- })
6
+ formatted_params = format_params(params)
7
+ post(url, formatted_params)
13
8
  end
14
9
 
10
+ private
11
+
12
+ def format_params(params)
13
+ if params.is_a?(Hash) && params.has_key?(:params)
14
+ params = params[:params]
15
+ return { params: base_params(params) }
16
+ else
17
+ return base_params(params)
18
+ end
19
+ end
20
+
21
+ def base_params(params)
22
+ return { job: {
23
+ callback_url: "callback_url",
24
+ params: params,
25
+ secret: "sekret",
26
+ }}
27
+ end
15
28
  end
16
29
  end
17
30
  end
@@ -1,5 +1,5 @@
1
1
  module Asyncapi
2
2
  module Server
3
- VERSION = "1.1.0"
3
+ VERSION = "1.3.0"
4
4
  end
5
5
  end
@@ -10,7 +10,7 @@ module Asyncapi
10
10
  it "returns all jobs" do
11
11
  job_1 = create(:asyncapi_server_job)
12
12
  job_2 = create(:asyncapi_server_job)
13
- get :index, format: :json, page: 2, per_page: 1
13
+ get :index, format: :json, params: { page: 2, per_page: 1 }
14
14
  expect(response).to be_successful
15
15
  parsed_result = indifferent_hash(response.body)
16
16
  expect(parsed_result.first[:id]).to eq job_2.id
@@ -21,7 +21,7 @@ module Asyncapi
21
21
  describe "GET show" do
22
22
  it "returns the job with the given id" do
23
23
  job = create(:asyncapi_server_job)
24
- get :show, format: :json, id: job.id
24
+ get :show, format: :json, params: { id: job.id }
25
25
  expect(response).to be_successful
26
26
  parsed_result = indifferent_hash(response.body)[:job]
27
27
  expect(parsed_result[:id]).to eq job.id
@@ -32,14 +32,14 @@ module Asyncapi
32
32
  describe "DELETE destroy" do
33
33
  it "finds the job by id and secret and deletes it" do
34
34
  job = create(:asyncapi_server_job, secret: "12312")
35
- delete :destroy, format: :json, id: job.id, secret: "12312"
35
+ delete :destroy, format: :json, params: { id: job.id, secret: "12312" }
36
36
  expect(response).to be_successful
37
37
  end
38
38
 
39
39
  context "secret does not match" do
40
40
  it "does not delete the job" do
41
41
  job = create(:asyncapi_server_job, secret: "12312")
42
- delete :destroy, format: :json, id: job.id, secret: "12315"
42
+ delete :destroy, format: :json, params: { id: job.id, secret: "12315" }
43
43
  expect(response.status).to eq 404
44
44
  end
45
45
  end
Binary file
@@ -11,9 +11,9 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20150201231329) do
14
+ ActiveRecord::Schema.define(version: 20150201231018) do
15
15
 
16
- create_table "asyncapi_server_jobs", force: true do |t|
16
+ create_table "asyncapi_server_jobs", force: :cascade do |t|
17
17
  t.integer "status"
18
18
  t.string "callback_url"
19
19
  t.string "class_name"
Binary file
@@ -0,0 +1,81 @@
1
+  (1.8ms) SELECT sqlite_version(*)
2
+  (1.6ms) SELECT sqlite_version(*)
3
+  (1.3ms) SELECT sqlite_version(*)
4
+  (1.3ms) SELECT sqlite_version(*)
5
+  (1.7ms) SELECT sqlite_version(*)
6
+  (1.7ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY)
7
+  (1.2ms) CREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL)
8
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
9
+ Migrating to CreateAsyncapiServerJobs (20141112034324)
10
+ TRANSACTION (0.1ms) begin transaction
11
+  (0.6ms) CREATE TABLE "asyncapi_server_jobs" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "status" integer, "callback_url" varchar, "class_name" varchar, "params" text)
12
+ ActiveRecord::SchemaMigration Create (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20141112034324"]]
13
+ TRANSACTION (0.8ms) commit transaction
14
+ Migrating to AddSecretToAsyncapiServerJob (20141212064931)
15
+ TRANSACTION (0.1ms) begin transaction
16
+  (0.6ms) ALTER TABLE "asyncapi_server_jobs" ADD "secret" varchar
17
+ ActiveRecord::SchemaMigration Create (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20141212064931"]]
18
+ TRANSACTION (1.3ms) commit transaction
19
+ Migrating to AddExpiredAtToAsyncapiServerJob (20150130062520)
20
+ TRANSACTION (0.1ms) begin transaction
21
+  (0.6ms) ALTER TABLE "asyncapi_server_jobs" ADD "expired_at" datetime
22
+ Asyncapi::Server::Job Update All (0.2ms) UPDATE "asyncapi_server_jobs" SET "expired_at" = ? WHERE "asyncapi_server_jobs"."expired_at" IS NULL [["expired_at", "2021-03-19 08:45:14.167931"]]
23
+ ActiveRecord::SchemaMigration Create (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20150130062520"]]
24
+ TRANSACTION (0.8ms) commit transaction
25
+ Migrating to DropExpiredAtFromAsyncapiServerJobs (20150201231018)
26
+ TRANSACTION (0.1ms) begin transaction
27
+  (0.1ms) PRAGMA foreign_keys
28
+  (0.1ms) PRAGMA defer_foreign_keys
29
+  (0.1ms) PRAGMA defer_foreign_keys = ON
30
+  (0.1ms) PRAGMA foreign_keys = OFF
31
+  (1.3ms) CREATE TEMPORARY TABLE "aasyncapi_server_jobs" ("id" integer NOT NULL PRIMARY KEY, "status" integer DEFAULT NULL, "callback_url" varchar DEFAULT NULL, "class_name" varchar DEFAULT NULL, "params" text DEFAULT NULL, "secret" varchar DEFAULT NULL, "expired_at" datetime DEFAULT NULL)
32
+  (0.1ms) INSERT INTO "aasyncapi_server_jobs" ("id","status","callback_url","class_name","params","secret","expired_at")
33
+ SELECT "id","status","callback_url","class_name","params","secret","expired_at" FROM "asyncapi_server_jobs"
34
+  (0.5ms) DROP TABLE "asyncapi_server_jobs"
35
+  (0.1ms) CREATE TABLE "asyncapi_server_jobs" ("id" integer NOT NULL PRIMARY KEY, "status" integer DEFAULT NULL, "callback_url" varchar DEFAULT NULL, "class_name" varchar DEFAULT NULL, "params" text DEFAULT NULL, "secret" varchar DEFAULT NULL)
36
+  (0.1ms) INSERT INTO "asyncapi_server_jobs" ("id","status","callback_url","class_name","params","secret")
37
+ SELECT "id","status","callback_url","class_name","params","secret" FROM "aasyncapi_server_jobs"
38
+  (0.1ms) DROP TABLE "aasyncapi_server_jobs"
39
+  (0.0ms) PRAGMA defer_foreign_keys = 0
40
+  (0.0ms) PRAGMA foreign_keys = 1
41
+ ActiveRecord::SchemaMigration Create (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20150201231018"]]
42
+ TRANSACTION (0.7ms) commit transaction
43
+ ActiveRecord::InternalMetadata Load (0.2ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
44
+ TRANSACTION (0.1ms) begin transaction
45
+ ActiveRecord::InternalMetadata Create (0.4ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["key", "environment"], ["value", "development"], ["created_at", "2021-03-09 08:45:14.199202"], ["updated_at", "2021-03-09 08:45:14.199202"]]
46
+ TRANSACTION (0.7ms) commit transaction
47
+  (0.1ms) SELECT sqlite_version(*)
48
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
49
+  (1.8ms) SELECT sqlite_version(*)
50
+  (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
51
+  (0.6ms) SELECT "ar_internal_metadata"."value" FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? [["key", "environment"]]
52
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
53
+  (0.1ms) SELECT "ar_internal_metadata"."value" FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? [["key", "environment"]]
54
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
55
+  (0.1ms) SELECT "ar_internal_metadata"."value" FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? [["key", "environment"]]
56
+  (0.1ms) SELECT sqlite_version(*)
57
+  (0.1ms) SELECT sqlite_version(*)
58
+  (0.1ms) DROP TABLE IF EXISTS "asyncapi_server_jobs"
59
+  (1.2ms) CREATE TABLE "asyncapi_server_jobs" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "status" integer, "callback_url" varchar, "class_name" varchar, "params" text, "secret" varchar)
60
+  (1.1ms) CREATE TABLE "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY)
61
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
62
+  (1.0ms) INSERT INTO "schema_migrations" (version) VALUES (20150201231018)
63
+  (1.2ms) INSERT INTO "schema_migrations" (version) VALUES
64
+ (20141112034324),
65
+ (20141212064931),
66
+ (20150130062520);
67
+
68
+ 
69
+  (1.2ms) CREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL)
70
+ ActiveRecord::InternalMetadata Load (0.2ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
71
+ TRANSACTION (0.1ms) begin transaction
72
+ ActiveRecord::InternalMetadata Create (0.4ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["key", "environment"], ["value", "development"], ["created_at", "2021-03-09 08:46:17.185916"], ["updated_at", "2021-03-09 08:46:17.185916"]]
73
+ TRANSACTION (0.7ms) commit transaction
74
+ ActiveRecord::InternalMetadata Load (0.1ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
75
+ TRANSACTION (0.0ms) begin transaction
76
+ ActiveRecord::InternalMetadata Update (0.3ms) UPDATE "ar_internal_metadata" SET "value" = ?, "updated_at" = ? WHERE "ar_internal_metadata"."key" = ? [["value", "test"], ["updated_at", "2021-03-09 08:46:17.189623"], ["key", "environment"]]
77
+ TRANSACTION (0.7ms) commit transaction
78
+ ActiveRecord::InternalMetadata Load (0.1ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "schema_sha1"], ["LIMIT", 1]]
79
+ TRANSACTION (0.0ms) begin transaction
80
+ ActiveRecord::InternalMetadata Create (0.3ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["key", "schema_sha1"], ["value", "b156e6c6d273062fcb56e7a3782b664b02612fc5"], ["created_at", "2021-03-09 08:46:17.192636"], ["updated_at", "2021-03-09 08:46:17.192636"]]
81
+ TRANSACTION (0.6ms) commit transaction