macaw_framework 1.1.0 → 1.1.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/CHANGELOG.md +7 -2
- data/README.md +55 -8
- data/SECURITY.md +3 -4
- data/lib/macaw_framework/core/{server.rb → common/server_base.rb} +26 -130
- data/lib/macaw_framework/core/cron_runner.rb +48 -0
- data/lib/macaw_framework/core/thread_server.rb +122 -0
- data/lib/macaw_framework/version.rb +1 -1
- data/lib/macaw_framework.rb +18 -3
- data/sig/cron_runner.rbs +6 -0
- data/sig/macaw_framework/macaw.rbs +1 -0
- metadata +6 -4
- data/macaw_logo.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7be8f35960be882dfd7d36d929a06a2ee46416e077532d6cb08809b39db41eed
|
4
|
+
data.tar.gz: 4ea88706237b89a02b64a7f6c73848d2b64c4ec04643e641ad6ac2711985f57d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a91371c336e35ad1207be16504767676ef1e2125cd40ea4caba201da704d2006a7bd538b77122502c90f85550142d11fc8d1c78c7a0426dd776f8e0b57a1b90
|
7
|
+
data.tar.gz: 67383dfb8aecb709167d5ab92af4cc9ed821e5898b92b2f06910ed8ccc2390af6afd7cc5325b7d1acf73fe3e731edf47afbbaa760e859fb3da92cae62103d8fd
|
data/CHANGELOG.md
CHANGED
@@ -68,9 +68,14 @@
|
|
68
68
|
|
69
69
|
- Fixing critical bug where threads were being killed and not respawning after abrupt client connection shutdown
|
70
70
|
|
71
|
-
## [1.1.0] - 2023-
|
71
|
+
## [1.1.0] - 2023-05-20
|
72
72
|
|
73
73
|
- Adding support for other SSL/TSL keys other than RSA
|
74
74
|
- New mechanism to handle server shutdown properly
|
75
75
|
- Improving log readability
|
76
|
-
- Automatic logging is now optional
|
76
|
+
- Automatic logging is now optional
|
77
|
+
|
78
|
+
## [1.1.1] - 2023-05-28
|
79
|
+
|
80
|
+
- Adding native cron jobs
|
81
|
+
- Documentation improvement
|
data/README.md
CHANGED
@@ -4,6 +4,22 @@ MacawFramework is a lightweight, easy-to-use web framework for Ruby designed to
|
|
4
4
|
medium-sized web applications. With support for various HTTP methods, caching, and session management, MacawFramework
|
5
5
|
provides developers with the essential tools to quickly build and deploy their applications.
|
6
6
|
|
7
|
+
- [MacawFramework](#macawframework)
|
8
|
+
* [Features](#features)
|
9
|
+
* [Installation](#installation)
|
10
|
+
* [Compatibility](#compatibility)
|
11
|
+
* [Usage](#usage)
|
12
|
+
+ [Basic routing: Define routes with support for GET, POST, PUT, PATCH, and DELETE HTTP methods](#basic-routing-define-routes-with-support-for-get-post-put-patch-and-delete-http-methods)
|
13
|
+
+ [Caching: Improve performance by caching responses and configuring cache invalidation](#caching-improve-performance-by-caching-responses-and-configuring-cache-invalidation)
|
14
|
+
+ [Session management: Handle user sessions securely with server-side in-memory storage](#session-management-handle-user-sessions-securely-with-server-side-in-memory-storage)
|
15
|
+
+ [Configuration: Customize various aspects of the framework through the application.json configuration file, such as rate limiting, SSL support, and Prometheus integration](#configuration-customize-various-aspects-of-the-framework-through-the-applicationjson-configuration-file-such-as-rate-limiting-ssl-support-and-prometheus-integration)
|
16
|
+
+ [Monitoring: Easily monitor your application performance and metrics with built-in Prometheus support](#monitoring-easily-monitor-your-application-performance-and-metrics-with-built-in-prometheus-support)
|
17
|
+
+ [Cron Jobs](#cron-jobs)
|
18
|
+
+ [Tips](#tips)
|
19
|
+
* [Contributing](#contributing)
|
20
|
+
* [License](#license)
|
21
|
+
* [Code of Conduct](#code-of-conduct)
|
22
|
+
|
7
23
|
## Features
|
8
24
|
|
9
25
|
- Simple routing with support for GET, POST, PUT, PATCH, and DELETE HTTP methods
|
@@ -23,6 +39,16 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
23
39
|
|
24
40
|
$ gem install macaw_framework
|
25
41
|
|
42
|
+
## Compatibility
|
43
|
+
|
44
|
+
MacawFramework is built to be highly compatible, since it uses only native Ruby code:
|
45
|
+
|
46
|
+
- **MRI**: MacawFramework is compatible with Matz's Ruby Interpreter (MRI), version 2.7.0 and onwards. If you are using this version or a more recent one, you should not encounter any compatibility issues.
|
47
|
+
|
48
|
+
- **TruffleRuby**: TruffleRuby is another Ruby interpreter that is fully compatible with MacawFramework. This provides developers with more flexibility in their choice of Ruby interpreter.
|
49
|
+
|
50
|
+
- **JRuby**: MacawFramework is also compatible with JRuby, a version of Ruby that runs on the Java Virtual Machine (JVM).
|
51
|
+
|
26
52
|
## Usage
|
27
53
|
|
28
54
|
### Basic routing: Define routes with support for GET, POST, PUT, PATCH, and DELETE HTTP methods
|
@@ -122,21 +148,39 @@ end
|
|
122
148
|
curl http://localhost:8080/metrics
|
123
149
|
```
|
124
150
|
|
151
|
+
### Cron Jobs
|
152
|
+
|
153
|
+
Macaw Framework supports the declaration of cron jobs right in your application code. This feature allows developers to
|
154
|
+
define tasks that run at set intervals, starting after an optional delay. Each job runs in a separate thread, meaning
|
155
|
+
your cron jobs can execute in parallel without blocking the rest of your application.
|
156
|
+
|
157
|
+
Here's an example of how to declare a cron job:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
m.setup_job(interval: 5, start_delay: 5, job_name: "cron job 1") do
|
161
|
+
puts "i'm a cron job that runs every 5 secs!"
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
Values for interval and start_delay are in seconds.
|
166
|
+
|
167
|
+
**Caution: Defining a lot of jobs with low interval can severely degrade performance.**
|
168
|
+
|
125
169
|
### Tips
|
126
170
|
|
127
|
-
The automatic logging and log aspect are now optional. To disable them, simply start Macaw with `custom_log` set to nil.
|
171
|
+
- The automatic logging and log aspect are now optional. To disable them, simply start Macaw with `custom_log` set to nil.
|
128
172
|
|
129
173
|
```ruby
|
130
174
|
MacawFramework::Macaw.new(custom_log: nil)
|
131
175
|
```
|
132
176
|
|
133
|
-
Cache invalidation time should be specified in seconds. In order to enable caching, The application.json file
|
177
|
+
- Cache invalidation time should be specified in seconds. In order to enable caching, The application.json file
|
134
178
|
should exist in the app main directory and it need the `cache_invalidation` config set. It is possible to
|
135
179
|
provide a list of strings in the property `ignore_headers`. All the client headers with the same name of any
|
136
180
|
of the strings provided will be ignored from caching strategy. This is useful to exclude headers like
|
137
181
|
correlation IDs from the caching strategy.
|
138
182
|
|
139
|
-
URL parameters like `...endOfUrl?key1=value1&key2=value2` can be find in the `context[:params]`
|
183
|
+
- URL parameters like `...endOfUrl?key1=value1&key2=value2` can be find in the `context[:params]`
|
140
184
|
|
141
185
|
```ruby
|
142
186
|
m.get('/test_params') do |context|
|
@@ -144,22 +188,25 @@ m.get('/test_params') do |context|
|
|
144
188
|
end
|
145
189
|
```
|
146
190
|
|
147
|
-
Rate Limit window should also be specified in seconds. Rate limit will be activated only if the `rate_limiting` config
|
191
|
+
- Rate Limit window should also be specified in seconds. Rate limit will be activated only if the `rate_limiting` config
|
148
192
|
exists inside `application.json`.
|
149
193
|
|
150
|
-
If the SSL configuration is provided in the `application.json` file with valid certificate and key files, the TCP server
|
194
|
+
- If the SSL configuration is provided in the `application.json` file with valid certificate and key files, the TCP server
|
151
195
|
will be wrapped with HTTPS security using the provided certificate.
|
152
196
|
|
153
|
-
The supported values for `min` and `max` in the SSL configuration are: `SSL2`, `SSL3`, `TLS1.1`, `TLS1.2` and `TLS1.3`,
|
197
|
+
- The supported values for `min` and `max` in the SSL configuration are: `SSL2`, `SSL3`, `TLS1.1`, `TLS1.2` and `TLS1.3`,
|
154
198
|
and the supported values for `key_type` are `RSA` and `EC`.
|
155
199
|
|
156
|
-
If prometheus is enabled, a get endpoint will be defined at path `/metrics` to collect prometheus metrics. This path
|
200
|
+
- If prometheus is enabled, a get endpoint will be defined at path `/metrics` to collect prometheus metrics. This path
|
157
201
|
is configurable via the `application.json` file.
|
158
202
|
|
159
|
-
The verb methods must always return a string or nil (used as the response), a number corresponding to the HTTP status
|
203
|
+
- The verb methods must always return a string or nil (used as the response), a number corresponding to the HTTP status
|
160
204
|
code to be returned to the client and the response headers as a Hash or nil. If an endpoint doesn't return a value or
|
161
205
|
returns nil for body, status code and headers, a default 200 OK status will be sent as the response.
|
162
206
|
|
207
|
+
- For cron jobs without a start_delay, a value of 0 will be used. For a job without name, a unique name will be generated
|
208
|
+
for it.
|
209
|
+
|
163
210
|
## Contributing
|
164
211
|
|
165
212
|
Bug reports and pull requests are welcome on GitHub at https://github.com/ariasdiniz/macaw_framework. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/ariasdiniz/macaw_framework/blob/main/CODE_OF_CONDUCT.md).
|
data/SECURITY.md
CHANGED
@@ -5,9 +5,9 @@
|
|
5
5
|
We are committed to addressing security issues in a timely manner. The following versions of MacawFramework are currently supported with security updates:
|
6
6
|
|
7
7
|
| Version | Supported |
|
8
|
-
|
9
|
-
| 1.
|
10
|
-
| < 1.
|
8
|
+
|---------| ------------------ |
|
9
|
+
| 1.x.x | :white_check_mark: |
|
10
|
+
| < 1.0 | :x: |
|
11
11
|
|
12
12
|
## Reporting a Vulnerability
|
13
13
|
|
@@ -24,4 +24,3 @@ Alternatively, you can send an email to aria.diniz.dev@gmail.com with the same i
|
|
24
24
|
4. Once the issue is resolved, we will release a new version of MacawFramework with the necessary security fixes.
|
25
25
|
|
26
26
|
Please remember to follow the project's [Code of Conduct](https://github.com/ariasdiniz/macaw_framework/blob/main/CODE_OF_CONDUCT.md) when reporting security vulnerabilities.
|
27
|
-
|
@@ -1,89 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
4
|
-
require_relative "
|
5
|
-
require_relative "
|
6
|
-
require_relative "
|
7
|
-
require_relative "
|
8
|
-
require_relative "
|
9
|
-
require_relative "
|
10
|
-
require_relative "
|
11
|
-
require "openssl"
|
3
|
+
require_relative "../../middlewares/memory_invalidation_middleware"
|
4
|
+
require_relative "../../middlewares/rate_limiter_middleware"
|
5
|
+
require_relative "../../data_filters/response_data_filter"
|
6
|
+
require_relative "../../errors/too_many_requests_error"
|
7
|
+
require_relative "../../utils/supported_ssl_versions"
|
8
|
+
require_relative "../../aspects/prometheus_aspect"
|
9
|
+
require_relative "../../aspects/logging_aspect"
|
10
|
+
require_relative "../../aspects/cache_aspect"
|
12
11
|
|
13
12
|
##
|
14
|
-
#
|
15
|
-
#
|
16
|
-
|
13
|
+
# Base module for Server classes. It contains
|
14
|
+
# methods for client handling, error handling,
|
15
|
+
# set features and every method that is common
|
16
|
+
# for the implementations of Servers.
|
17
|
+
module ServerBase
|
17
18
|
prepend CacheAspect
|
18
19
|
prepend LoggingAspect
|
19
20
|
prepend PrometheusAspect
|
20
|
-
# rubocop:disable Metrics/ParameterLists
|
21
|
-
|
22
|
-
attr_reader :context
|
23
|
-
|
24
|
-
##
|
25
|
-
# Create a new instance of Server.
|
26
|
-
# @param {Macaw} macaw
|
27
|
-
# @param {Logger} logger
|
28
|
-
# @param {Integer} port
|
29
|
-
# @param {String} bind
|
30
|
-
# @param {Integer} num_threads
|
31
|
-
# @param {MemoryInvalidationMiddleware} cache
|
32
|
-
# @param {Prometheus::Client:Registry} prometheus
|
33
|
-
# @return {Server}
|
34
|
-
def initialize(macaw, endpoints_to_cache = nil, cache = nil, prometheus = nil, prometheus_mw = nil)
|
35
|
-
@port = macaw.port
|
36
|
-
@bind = macaw.bind
|
37
|
-
@macaw = macaw
|
38
|
-
@macaw_log = macaw.macaw_log
|
39
|
-
@num_threads = macaw.threads
|
40
|
-
@work_queue = Queue.new
|
41
|
-
ignored_headers = set_cache_ignored_h
|
42
|
-
set_features
|
43
|
-
@rate_limit ||= nil
|
44
|
-
ignored_headers ||= nil
|
45
|
-
@cache = { cache: cache, endpoints_to_cache: endpoints_to_cache || [], ignored_headers: ignored_headers }
|
46
|
-
@prometheus = prometheus
|
47
|
-
@prometheus_middleware = prometheus_mw
|
48
|
-
@workers = []
|
49
|
-
end
|
50
|
-
|
51
|
-
# rubocop:enable Metrics/ParameterLists
|
52
|
-
|
53
|
-
##
|
54
|
-
# Start running the webserver.
|
55
|
-
def run
|
56
|
-
@server = TCPServer.new(@bind, @port)
|
57
|
-
@server = OpenSSL::SSL::SSLServer.new(@server, @context) if @context
|
58
|
-
@workers_mutex = Mutex.new
|
59
|
-
@num_threads.times do
|
60
|
-
spawn_worker
|
61
|
-
end
|
62
21
|
|
63
|
-
|
64
|
-
loop do
|
65
|
-
sleep 10
|
66
|
-
maintain_worker_pool
|
67
|
-
end
|
68
|
-
end
|
22
|
+
private
|
69
23
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
24
|
+
def call_endpoint(name, client_data, client_ip)
|
25
|
+
@macaw.send(
|
26
|
+
name.to_sym,
|
27
|
+
{
|
28
|
+
headers: client_data[:headers],
|
29
|
+
body: client_data[:body],
|
30
|
+
params: client_data[:params],
|
31
|
+
client: @session[client_ip][0]
|
32
|
+
}
|
33
|
+
)
|
77
34
|
end
|
78
35
|
|
79
|
-
|
80
|
-
|
81
|
-
def close
|
82
|
-
shutdown
|
36
|
+
def get_client_data(body, headers, parameters)
|
37
|
+
{ body: body, headers: headers, params: parameters }
|
83
38
|
end
|
84
39
|
|
85
|
-
private
|
86
|
-
|
87
40
|
def handle_client(client)
|
88
41
|
path, method_name, headers, body, parameters = RequestDataFiltering.parse_request_data(client, @macaw.routes)
|
89
42
|
raise EndpointNotMappedError unless @macaw.respond_to?(method_name)
|
@@ -178,61 +131,4 @@ class Server
|
|
178
131
|
set_session
|
179
132
|
set_ssl
|
180
133
|
end
|
181
|
-
|
182
|
-
def call_endpoint(name, client_data, client_ip)
|
183
|
-
@macaw.send(
|
184
|
-
name.to_sym,
|
185
|
-
{
|
186
|
-
headers: client_data[:headers],
|
187
|
-
body: client_data[:body],
|
188
|
-
params: client_data[:params],
|
189
|
-
client: @session[client_ip][0]
|
190
|
-
}
|
191
|
-
)
|
192
|
-
end
|
193
|
-
|
194
|
-
def get_client_data(body, headers, parameters)
|
195
|
-
{ body: body, headers: headers, params: parameters }
|
196
|
-
end
|
197
|
-
|
198
|
-
def spawn_worker
|
199
|
-
@workers_mutex.synchronize do
|
200
|
-
@workers << Thread.new do
|
201
|
-
loop do
|
202
|
-
client = @work_queue.pop
|
203
|
-
break if client == :shutdown
|
204
|
-
|
205
|
-
handle_client(client)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def maintain_worker_pool
|
212
|
-
@workers_mutex.synchronize do
|
213
|
-
@workers.each_with_index do |worker, index|
|
214
|
-
unless worker.alive?
|
215
|
-
if @is_shutting_down
|
216
|
-
@macaw_log&.info("Worker thread #{index} finished, not respawning due to server shutdown.")
|
217
|
-
else
|
218
|
-
@macaw_log&.error("Worker thread #{index} died, respawning...")
|
219
|
-
@workers[index] = spawn_worker
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def shutdown
|
227
|
-
@is_shutting_down = true
|
228
|
-
loop do
|
229
|
-
break if @work_queue.empty?
|
230
|
-
|
231
|
-
sleep 0.1
|
232
|
-
end
|
233
|
-
|
234
|
-
@num_threads.times { @work_queue << :shutdown }
|
235
|
-
@workers.each(&:join)
|
236
|
-
@server.close
|
237
|
-
end
|
238
134
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# This module is responsible to set up a new thread
|
5
|
+
# for each cron job defined
|
6
|
+
class CronRunner
|
7
|
+
def initialize(macaw)
|
8
|
+
@logger = macaw.macaw_log
|
9
|
+
@macaw = macaw
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Will start a thread for the defined cron job
|
14
|
+
# @param {Integer} interval
|
15
|
+
# @param {Integer?} start_delay
|
16
|
+
# @param {String} job_name
|
17
|
+
# @param {Proc} block
|
18
|
+
def start_cron_job_thread(interval, start_delay, job_name, &block)
|
19
|
+
raise "interval can't be <= 0 and start_delay can't be < 0!" if interval <= 0 || start_delay.negative?
|
20
|
+
|
21
|
+
@logger&.info("Starting thread for job #{job_name}")
|
22
|
+
start_delay ||= 0
|
23
|
+
thread = Thread.new do
|
24
|
+
name = job_name
|
25
|
+
interval_thread = interval
|
26
|
+
unless start_delay.nil?
|
27
|
+
@logger&.info("Job #{name} scheduled with delay. Will start running in #{start_delay} seconds.")
|
28
|
+
sleep(start_delay)
|
29
|
+
end
|
30
|
+
|
31
|
+
loop do
|
32
|
+
start_time = Time.now
|
33
|
+
@logger&.info("Running job #{name}")
|
34
|
+
block.call
|
35
|
+
@logger&.info("Job #{name} executed with success. New execution in #{interval_thread} seconds.")
|
36
|
+
|
37
|
+
execution_time = Time.now - start_time
|
38
|
+
sleep_time = [interval_thread - execution_time, 0].max
|
39
|
+
sleep(sleep_time)
|
40
|
+
rescue StandardError => e
|
41
|
+
@logger&.error("Error executing cron job with name #{name}: #{e.message}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
sleep(1)
|
45
|
+
@logger&.info("Thread for job #{job_name} started")
|
46
|
+
thread
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "common/server_base"
|
4
|
+
require "openssl"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Class responsible for providing a default
|
8
|
+
# webserver with Ruby Threads. This Server is subject
|
9
|
+
# to the MRI Global Interpreter Lock, thus it will use
|
10
|
+
# only a single physical Thread. For a true multi threaded
|
11
|
+
# server, check the RactorServer.
|
12
|
+
class ThreadServer
|
13
|
+
include ServerBase
|
14
|
+
|
15
|
+
attr_reader :context
|
16
|
+
|
17
|
+
# rubocop:disable Metrics/ParameterLists
|
18
|
+
|
19
|
+
##
|
20
|
+
# Create a new instance of ThreadServer.
|
21
|
+
# @param {Macaw} macaw
|
22
|
+
# @param {Logger} logger
|
23
|
+
# @param {Integer} port
|
24
|
+
# @param {String} bind
|
25
|
+
# @param {Integer} num_threads
|
26
|
+
# @param {MemoryInvalidationMiddleware} cache
|
27
|
+
# @param {Prometheus::Client:Registry} prometheus
|
28
|
+
# @return {Server}
|
29
|
+
def initialize(macaw, endpoints_to_cache = nil, cache = nil, prometheus = nil, prometheus_mw = nil)
|
30
|
+
@port = macaw.port
|
31
|
+
@bind = macaw.bind
|
32
|
+
@macaw = macaw
|
33
|
+
@macaw_log = macaw.macaw_log
|
34
|
+
@num_threads = macaw.threads
|
35
|
+
@work_queue = Queue.new
|
36
|
+
ignored_headers = set_cache_ignored_h
|
37
|
+
set_features
|
38
|
+
@rate_limit ||= nil
|
39
|
+
ignored_headers ||= nil
|
40
|
+
@cache = { cache: cache, endpoints_to_cache: endpoints_to_cache || [], ignored_headers: ignored_headers }
|
41
|
+
@prometheus = prometheus
|
42
|
+
@prometheus_middleware = prometheus_mw
|
43
|
+
@workers = []
|
44
|
+
end
|
45
|
+
|
46
|
+
# rubocop:enable Metrics/ParameterLists
|
47
|
+
|
48
|
+
##
|
49
|
+
# Start running the webserver.
|
50
|
+
def run
|
51
|
+
@server = TCPServer.new(@bind, @port)
|
52
|
+
@server = OpenSSL::SSL::SSLServer.new(@server, @context) if @context
|
53
|
+
@workers_mutex = Mutex.new
|
54
|
+
@num_threads.times do
|
55
|
+
spawn_worker
|
56
|
+
end
|
57
|
+
|
58
|
+
Thread.new do
|
59
|
+
loop do
|
60
|
+
sleep 10
|
61
|
+
maintain_worker_pool
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
loop do
|
66
|
+
@work_queue << @server.accept
|
67
|
+
rescue OpenSSL::SSL::SSLError => e
|
68
|
+
@macaw_log&.error("SSL error: #{e.message}")
|
69
|
+
rescue IOError, Errno::EBADF
|
70
|
+
break
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Method Responsible for closing the TCP server.
|
76
|
+
def close
|
77
|
+
shutdown
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def spawn_worker
|
83
|
+
@workers_mutex.synchronize do
|
84
|
+
@workers << Thread.new do
|
85
|
+
loop do
|
86
|
+
client = @work_queue.pop
|
87
|
+
break if client == :shutdown
|
88
|
+
|
89
|
+
handle_client(client)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def maintain_worker_pool
|
96
|
+
@workers_mutex.synchronize do
|
97
|
+
@workers.each_with_index do |worker, index|
|
98
|
+
unless worker.alive?
|
99
|
+
if @is_shutting_down
|
100
|
+
@macaw_log&.info("Worker thread #{index} finished, not respawning due to server shutdown.")
|
101
|
+
else
|
102
|
+
@macaw_log&.error("Worker thread #{index} died, respawning...")
|
103
|
+
@workers[index] = spawn_worker
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def shutdown
|
111
|
+
@is_shutting_down = true
|
112
|
+
loop do
|
113
|
+
break if @work_queue.empty?
|
114
|
+
|
115
|
+
sleep 0.1
|
116
|
+
end
|
117
|
+
|
118
|
+
@num_threads.times { @work_queue << :shutdown }
|
119
|
+
@workers.each(&:join)
|
120
|
+
@server.close
|
121
|
+
end
|
122
|
+
end
|
data/lib/macaw_framework.rb
CHANGED
@@ -4,9 +4,11 @@ require_relative "macaw_framework/errors/endpoint_not_mapped_error"
|
|
4
4
|
require_relative "macaw_framework/middlewares/prometheus_middleware"
|
5
5
|
require_relative "macaw_framework/data_filters/request_data_filtering"
|
6
6
|
require_relative "macaw_framework/middlewares/memory_invalidation_middleware"
|
7
|
-
require_relative "macaw_framework/core/
|
7
|
+
require_relative "macaw_framework/core/cron_runner"
|
8
|
+
require_relative "macaw_framework/core/thread_server"
|
8
9
|
require_relative "macaw_framework/version"
|
9
10
|
require "prometheus/client"
|
11
|
+
require "securerandom"
|
10
12
|
require "logger"
|
11
13
|
require "socket"
|
12
14
|
require "json"
|
@@ -18,11 +20,11 @@ module MacawFramework
|
|
18
20
|
class Macaw
|
19
21
|
##
|
20
22
|
# Array containing the routes defined in the application
|
21
|
-
attr_reader :routes, :port, :bind, :threads, :macaw_log, :config
|
23
|
+
attr_reader :routes, :port, :bind, :threads, :macaw_log, :config, :jobs
|
22
24
|
|
23
25
|
##
|
24
26
|
# @param {Logger} custom_log
|
25
|
-
def initialize(custom_log: Logger.new($stdout), server:
|
27
|
+
def initialize(custom_log: Logger.new($stdout), server: ThreadServer)
|
26
28
|
begin
|
27
29
|
@routes = []
|
28
30
|
@macaw_log ||= custom_log
|
@@ -100,6 +102,19 @@ module MacawFramework
|
|
100
102
|
map_new_endpoint("delete", cache, path, &block)
|
101
103
|
end
|
102
104
|
|
105
|
+
##
|
106
|
+
# Spawn and start a thread running the defined cron job.
|
107
|
+
# @param {Integer} interval
|
108
|
+
# @param {Integer?} start_delay
|
109
|
+
# @param {String} job_name
|
110
|
+
# @param {Proc} block
|
111
|
+
def setup_job(interval: 60, start_delay: nil, job_name: "job_#{SecureRandom.uuid}", &block)
|
112
|
+
@cron_runner ||= CronRunner.new(self)
|
113
|
+
@jobs ||= []
|
114
|
+
@cron_runner.start_cron_job_thread(interval, start_delay, job_name, &block)
|
115
|
+
@jobs << job_name
|
116
|
+
end
|
117
|
+
|
103
118
|
##
|
104
119
|
# Starts the web server
|
105
120
|
def start!
|
data/sig/cron_runner.rbs
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: macaw_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aria Diniz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prometheus-client
|
@@ -46,7 +46,9 @@ files:
|
|
46
46
|
- lib/macaw_framework/aspects/cache_aspect.rb
|
47
47
|
- lib/macaw_framework/aspects/logging_aspect.rb
|
48
48
|
- lib/macaw_framework/aspects/prometheus_aspect.rb
|
49
|
-
- lib/macaw_framework/core/
|
49
|
+
- lib/macaw_framework/core/common/server_base.rb
|
50
|
+
- lib/macaw_framework/core/cron_runner.rb
|
51
|
+
- lib/macaw_framework/core/thread_server.rb
|
50
52
|
- lib/macaw_framework/data_filters/log_data_filter.rb
|
51
53
|
- lib/macaw_framework/data_filters/request_data_filtering.rb
|
52
54
|
- lib/macaw_framework/data_filters/response_data_filter.rb
|
@@ -58,8 +60,8 @@ files:
|
|
58
60
|
- lib/macaw_framework/utils/http_status_code.rb
|
59
61
|
- lib/macaw_framework/utils/supported_ssl_versions.rb
|
60
62
|
- lib/macaw_framework/version.rb
|
61
|
-
- macaw_logo.png
|
62
63
|
- main/CODEOWNERS
|
64
|
+
- sig/cron_runner.rbs
|
63
65
|
- sig/http_status_code.rbs
|
64
66
|
- sig/logging_aspect.rbs
|
65
67
|
- sig/macaw_framework.rbs
|
data/macaw_logo.png
DELETED
Binary file
|