ru.Bee 1.8.0 → 1.9.1
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.
- checksums.yaml +4 -4
- data/lib/config/base_configuration.rb +15 -0
- data/lib/rubee/autoload.rb +4 -0
- data/lib/rubee/cli/generate.rb +1 -2
- data/lib/rubee/cli/routes.rb +1 -2
- data/lib/rubee/configuration.rb +15 -0
- data/lib/rubee/models/db_tools.rb +36 -0
- data/lib/rubee/models/sequel_object.rb +6 -2
- data/lib/rubee.rb +1 -1
- data/lib/tests/models/user_model_test.rb +26 -1
- data/lib/tests/test.db +0 -0
- data/readme.md +25 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a599b63001f79ac7d562e987e30851136783b443f876ac490f99aa5ae0a1920
|
4
|
+
data.tar.gz: dd558714f74ba57d6c0df9266ed62b2d08c3b75c1826c4ad2ac3604caaa34810
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a591e728a7a1f50f1844770020c0dcd5197c79429b15b203f1f9687b9d66ad22ca54b4ccaf7f9cb440c70ade30f9b45820c27d0f8c4c9f25a5c80414e361db30
|
7
|
+
data.tar.gz: '094effa1b6595ff6c2c8f72bd7fa41a6ba95d6017592887eecffae7e308fd4d7f90009b67264f249fd8b851d8b7e414b1d1f2222214aaa9ca230b0e7ca4c0a2c'
|
@@ -10,6 +10,11 @@ Rubee::Configuration.setup(env = :development) do |config|
|
|
10
10
|
|
11
11
|
## configure logger
|
12
12
|
# config.logger = { logger: MyLogger, env: }
|
13
|
+
|
14
|
+
## configure db write retries
|
15
|
+
# config.db_max_retries = { env:, value: 3 }
|
16
|
+
# config.db_retry_delay = { env:, value: 0.1 }
|
17
|
+
# config.db_busy_timeout = { env:, value: 2000 }
|
13
18
|
end
|
14
19
|
|
15
20
|
Rubee::Configuration.setup(env = :test) do |config|
|
@@ -24,6 +29,11 @@ Rubee::Configuration.setup(env = :test) do |config|
|
|
24
29
|
|
25
30
|
## configure logger
|
26
31
|
# config.logger = { logger: MyLogger, env: }
|
32
|
+
|
33
|
+
## configure db write retries
|
34
|
+
# config.db_max_retries = { env:, value: 3 }
|
35
|
+
# config.db_retry_delay = { env:, value: 0.1 }
|
36
|
+
# config.db_busy_timeout = { env:, value: 2000 }
|
27
37
|
end
|
28
38
|
|
29
39
|
Rubee::Configuration.setup(env = :production) do |config|
|
@@ -38,4 +48,9 @@ Rubee::Configuration.setup(env = :production) do |config|
|
|
38
48
|
|
39
49
|
## configure logger
|
40
50
|
# config.logger = { logger: MyLogger, env: }
|
51
|
+
|
52
|
+
## configure db write retries
|
53
|
+
# config.db_max_retries = { env:, value: 3 }
|
54
|
+
# config.db_retry_delay = { env:, value: 0.1 }
|
55
|
+
# config.db_busy_timeout = { env:, value: 2000 }
|
41
56
|
end
|
data/lib/rubee/autoload.rb
CHANGED
@@ -76,6 +76,10 @@ module Rubee
|
|
76
76
|
|
77
77
|
require_relative File.join(root_directory,
|
78
78
|
'rubee/models/sequel_object')
|
79
|
+
return if black_list.include?('db_tools.rb')
|
80
|
+
|
81
|
+
require_relative File.join(root_directory,
|
82
|
+
'rubee/models/db_tools')
|
79
83
|
|
80
84
|
Dir[File.join(root_directory, 'rubee/cli/**', '*.rb')].each do |file|
|
81
85
|
require_relative file
|
data/lib/rubee/cli/generate.rb
CHANGED
@@ -11,8 +11,7 @@ module Rubee
|
|
11
11
|
app = argv[3]
|
12
12
|
app_name = app.nil? ? :app : app.split(':')[1]
|
13
13
|
ENV['RACK_ENV'] ||= 'development'
|
14
|
-
|
15
|
-
routes = eval(File.read(file))
|
14
|
+
routes = Rubee::Router.instance_variable_get(:@routes)
|
16
15
|
route = routes.find { |route| route[:path] == path.to_s && route[:method] == method.to_sym }
|
17
16
|
|
18
17
|
color_puts("Route not found with path: #{path} and method: #{method}", color: :red) unless route
|
data/lib/rubee/cli/routes.rb
CHANGED
@@ -7,8 +7,7 @@ module Rubee
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def routes(_argv)
|
10
|
-
|
11
|
-
routes = eval(File.read(file)) # TODO: rewrite it omitting eval
|
10
|
+
routes = Rubee::Router.instance_variable_get(:@routes)
|
12
11
|
|
13
12
|
color_puts(routes, color: :green)
|
14
13
|
end
|
data/lib/rubee/configuration.rb
CHANGED
@@ -51,6 +51,21 @@ module Rubee
|
|
51
51
|
@configuraiton[args[:app].to_sym][args[:env].to_sym][:fiber_pool_limit] = args[:value]
|
52
52
|
end
|
53
53
|
|
54
|
+
def db_max_retries=(args)
|
55
|
+
args[:app] ||= :app
|
56
|
+
@configuraiton[args[:app].to_sym][args[:env].to_sym][:db_max_retries] = args[:value]
|
57
|
+
end
|
58
|
+
|
59
|
+
def db_retry_delay=(args)
|
60
|
+
args[:app] ||= :app
|
61
|
+
@configuraiton[args[:app].to_sym][args[:env].to_sym][:db_retry_delay] = args[:value]
|
62
|
+
end
|
63
|
+
|
64
|
+
def db_busy_timeout=(args)
|
65
|
+
args[:app] ||= :app
|
66
|
+
@configuraiton[args[:app].to_sym][args[:env].to_sym][:db_busy_timeout] = args[:value]
|
67
|
+
end
|
68
|
+
|
54
69
|
def logger=(args)
|
55
70
|
args[:app] ||= :app
|
56
71
|
@configuraiton[args[:app].to_sym][args[:env].to_sym][:logger] = args[:logger]
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Rubee
|
2
|
+
module DBTools
|
3
|
+
MAX_RETRIES = Rubee::Configuration.get_db_max_retries || 3
|
4
|
+
DELAY = Rubee::Configuration.get_db_retry_delay || 0.1
|
5
|
+
BUSY_TIMEOUT = Rubee::Configuration.get_db_busy_timeout || 2000
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def with_retry
|
9
|
+
retries = 0
|
10
|
+
begin
|
11
|
+
yield
|
12
|
+
rescue Sequel::DatabaseError => e
|
13
|
+
# Applicable for msqlite only, however it can be extended in the future
|
14
|
+
if Rubee::SequelObject::DB.adapter_scheme == :sqlite &&
|
15
|
+
e.cause.is_a?(SQLite3::BusyException) && retries < MAX_RETRIES
|
16
|
+
retries += 1
|
17
|
+
sleep(DELAY)
|
18
|
+
retry
|
19
|
+
else
|
20
|
+
raise e
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_prerequisites!
|
26
|
+
# Necessary changes to make sqlite be none blocking
|
27
|
+
if Rubee::SequelObject::DB.adapter_scheme == :sqlite
|
28
|
+
# WAL mode allows concurrent reads and non-blocking writes.
|
29
|
+
Rubee::SequelObject::DB.execute("PRAGMA journal_mode = WAL")
|
30
|
+
# Wait 2000ms for a write lock.
|
31
|
+
Rubee::SequelObject::DB.execute("PRAGMA busy_timeout = #{BUSY_TIMEOUT}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -50,7 +50,7 @@ module Rubee
|
|
50
50
|
def update(args = {})
|
51
51
|
assign_attributes(args)
|
52
52
|
found_hash = self.class.dataset.where(id:)
|
53
|
-
return self.class.find(id) if found_hash&.update(**args)
|
53
|
+
return self.class.find(id) if Rubee::DBTools.with_retry { found_hash&.update(**args) }
|
54
54
|
|
55
55
|
false
|
56
56
|
end
|
@@ -130,6 +130,10 @@ module Rubee
|
|
130
130
|
return if defined?(DB) && !DB.nil?
|
131
131
|
|
132
132
|
const_set(:DB, Sequel.connect(Rubee::Configuration.get_database_url))
|
133
|
+
|
134
|
+
Rubee::DBTools.set_prerequisites!
|
135
|
+
|
136
|
+
true
|
133
137
|
end
|
134
138
|
|
135
139
|
def dataset
|
@@ -169,7 +173,7 @@ module Rubee
|
|
169
173
|
end
|
170
174
|
|
171
175
|
def create(attrs)
|
172
|
-
out_id = dataset.insert(**attrs)
|
176
|
+
out_id = Rubee::DBTools.with_retry { dataset.insert(**attrs) }
|
173
177
|
new(**attrs.merge(id: out_id))
|
174
178
|
end
|
175
179
|
|
data/lib/rubee.rb
CHANGED
@@ -16,7 +16,7 @@ module Rubee
|
|
16
16
|
JS_DIR = File.join(APP_ROOT, LIB, 'js') unless defined?(JS_DIR)
|
17
17
|
CSS_DIR = File.join(APP_ROOT, LIB, 'css') unless defined?(CSS_DIR)
|
18
18
|
ROOT_PATH = File.expand_path(File.join(__dir__, '..')) unless defined?(ROOT_PATH)
|
19
|
-
VERSION = '1.
|
19
|
+
VERSION = '1.9.0'
|
20
20
|
|
21
21
|
require_relative 'rubee/router'
|
22
22
|
require_relative 'rubee/logger'
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative '../test_helper'
|
2
|
-
|
3
2
|
describe 'User model' do
|
4
3
|
describe '.create' do
|
5
4
|
after do
|
@@ -68,6 +67,32 @@ describe 'User model' do
|
|
68
67
|
_(User.all.count).must_equal(initial_count)
|
69
68
|
end
|
70
69
|
end
|
70
|
+
|
71
|
+
describe 'locking model' do
|
72
|
+
before do
|
73
|
+
User.destroy_all(cascade: true)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'triggers save two times' do
|
77
|
+
t1 = Thread.new do
|
78
|
+
User::DB.transaction do
|
79
|
+
user2 = User.new(email: 'holding-lock2@example.com', password: '125')
|
80
|
+
sleep(0.5)
|
81
|
+
user2.save
|
82
|
+
end
|
83
|
+
end
|
84
|
+
sleep(0.1)
|
85
|
+
t2 = Thread.new do
|
86
|
+
user1 = User.new(email: 'holding-lock@example.com', password: '123')
|
87
|
+
user1.save
|
88
|
+
end
|
89
|
+
|
90
|
+
t1.join
|
91
|
+
t2.join
|
92
|
+
|
93
|
+
_(User.all.count).must_equal(2)
|
94
|
+
end
|
95
|
+
end
|
71
96
|
end
|
72
97
|
|
73
98
|
describe '.update' do
|
data/lib/tests/test.db
CHANGED
Binary file
|
data/readme.md
CHANGED
@@ -100,6 +100,11 @@ bundle install
|
|
100
100
|
4. Run ruBee server. Default port is 7000
|
101
101
|
```bash
|
102
102
|
rubee start # or rubee start_dev for development
|
103
|
+
|
104
|
+
# Sarting from veriosn 1.8.0, you can also start you rubee server with yjit compiler and enjoy speed boost.
|
105
|
+
rubee start --yjit
|
106
|
+
# Option is available for dev environment too
|
107
|
+
rubee start_dev --yjit
|
103
108
|
```
|
104
109
|
|
105
110
|
5. Open your browser and go to http://localhost:7000
|
@@ -334,6 +339,25 @@ So it may safe some resources.
|
|
334
339
|
|
335
340
|
[Back to content](#content)
|
336
341
|
|
342
|
+
## Mysqlite production ready
|
343
|
+
Starting from verison 1.9.0 main issue for using sqlite - write db lock is resolved!
|
344
|
+
If you feel comfortable you can play with retry configuration parameters:
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
## configure db write retries
|
348
|
+
config.db_max_retries = { env:, value: 3 } # set it to 0 to disable or increase if needed
|
349
|
+
config.db_retry_delay = { env:, value: 0.1 }
|
350
|
+
config.db_busy_timeout = { env:, value: 1000 } # this is busy timeout in ms, before raising bussy error
|
351
|
+
```
|
352
|
+
|
353
|
+
For Rubee model class persist methods create and update retry will be added automatically. However, \
|
354
|
+
if you want to do it with Sequel dataset you need to do it yourself:
|
355
|
+
|
356
|
+
```ruby
|
357
|
+
Rubee::DBTools.with_retry { User.dataset.insert(email: "test@ok.com", password: "123") }
|
358
|
+
```
|
359
|
+
[Back to content](#content)
|
360
|
+
|
337
361
|
## Routing
|
338
362
|
Rubee uses explicit routes. In the routes.rb yout can define routes for any of the main HTTP methods. \
|
339
363
|
You can also add any matched parameter denoted by a pair of `{ }` in the path of the route. \
|
@@ -971,4 +995,4 @@ Have an idea or you wnat to discuss something?
|
|
971
995
|
Please open a [discussion](https://github.com/nucleom42/rubee/discussions)
|
972
996
|
|
973
997
|
## License
|
974
|
-
This project is released under the MIT License.
|
998
|
+
This project is released under the [MIT License](https://github.com/nucleom42/rubee/blob/main/LICENSE).
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ru.Bee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Saltykov
|
@@ -255,6 +255,7 @@ files:
|
|
255
255
|
- lib/rubee/generator.rb
|
256
256
|
- lib/rubee/logger.rb
|
257
257
|
- lib/rubee/models/database_objectable.rb
|
258
|
+
- lib/rubee/models/db_tools.rb
|
258
259
|
- lib/rubee/models/sequel_object.rb
|
259
260
|
- lib/rubee/router.rb
|
260
261
|
- lib/tests/async/thread_async_test.rb
|