functions_framework 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/docs/overview.md +1 -1
- data/docs/writing-functions.md +60 -12
- data/lib/functions_framework/cli.rb +1 -1
- data/lib/functions_framework/function.rb +53 -5
- data/lib/functions_framework/legacy_event_converter.rb +8 -5
- data/lib/functions_framework/server.rb +1 -1
- data/lib/functions_framework/testing.rb +3 -2
- data/lib/functions_framework/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d313c253cf23573fe55628885064699cf1da8ca51545446cd3a6adf58ffaf3ff
|
4
|
+
data.tar.gz: 2b82761a46c066f2a32af713c85e559afe5fe892bc1c761ec765772dd2633db2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b58f6f2c3fbebf5cf6c5eb28031a4ec7a389c063b9f2b8edba6b7e346f20683a8a9339202e8075299c67c5a347313c37bd82aac47422981008858e301133cccf
|
7
|
+
data.tar.gz: fbd5515ed316ab193eec32efe17eb66cc937582d1af9b6196854bac8d2dee16de6d0b7429aac66ce287b97043b5dfadc35d989451e7bb3495d62dee512cd1681
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -60,7 +60,7 @@ Create a `Gemfile` listing the Functions Framework as a dependency:
|
|
60
60
|
```ruby
|
61
61
|
# Gemfile
|
62
62
|
source "https://rubygems.org"
|
63
|
-
gem "functions_framework", "~> 0.
|
63
|
+
gem "functions_framework", "~> 0.8"
|
64
64
|
```
|
65
65
|
|
66
66
|
Create a file called `app.rb` and include the following code. This defines a
|
data/docs/overview.md
CHANGED
@@ -64,7 +64,7 @@ Create a `Gemfile` listing the Functions Framework as a dependency:
|
|
64
64
|
```ruby
|
65
65
|
# Gemfile
|
66
66
|
source "https://rubygems.org"
|
67
|
-
gem "functions_framework", "~> 0.
|
67
|
+
gem "functions_framework", "~> 0.8"
|
68
68
|
```
|
69
69
|
|
70
70
|
Create a file called `app.rb` and include the following code. This defines a
|
data/docs/writing-functions.md
CHANGED
@@ -111,7 +111,7 @@ dependency on Sinatra in your `Gemfile`:
|
|
111
111
|
|
112
112
|
```ruby
|
113
113
|
source "https://rubygems.org"
|
114
|
-
gem "functions_framework", "~> 0.
|
114
|
+
gem "functions_framework", "~> 0.8"
|
115
115
|
gem "sinatra", "~> 2.0"
|
116
116
|
```
|
117
117
|
|
@@ -248,10 +248,10 @@ FunctionsFramework.http "hello" do |request|
|
|
248
248
|
end
|
249
249
|
```
|
250
250
|
|
251
|
-
Startup tasks are run once per Ruby instance
|
252
|
-
|
253
|
-
|
254
|
-
function is executed.
|
251
|
+
Startup tasks are run once per Ruby instance during cold start -- that is,
|
252
|
+
after the Ruby VM boots up but before the framework starts receiving requests
|
253
|
+
and executing functions. You can define multiple startup tasks, and they will
|
254
|
+
run in order, and are guaranteed to complete before any function is executed.
|
255
255
|
|
256
256
|
The block is optionally passed the {FunctionsFramework::Function} representing
|
257
257
|
the function that will be run. You code can, for example, perform different
|
@@ -286,6 +286,11 @@ end
|
|
286
286
|
# ...
|
287
287
|
```
|
288
288
|
|
289
|
+
Because startup tasks run during cold start, they could have an impact on your
|
290
|
+
function's startup latency. To mitigate this issue, it is possible to run parts
|
291
|
+
of your initialization lazily, as described below in the section below on
|
292
|
+
[lazy initialization](#Lazy_initialization).
|
293
|
+
|
289
294
|
### The execution context and global data
|
290
295
|
|
291
296
|
When your function block executes, the _object context_ (i.e. `self`) is set to
|
@@ -331,8 +336,9 @@ resources, as described below.
|
|
331
336
|
Using the global data mechanism is generally preferred over actual Ruby global
|
332
337
|
variables, because the Functions Framework can help you avoid concurrent edits.
|
333
338
|
Additionally, the framework will isolate the sets of global data associated
|
334
|
-
with different sets of functions, which lets you
|
335
|
-
|
339
|
+
with different sets of functions, which lets you run functions in isolation
|
340
|
+
during unit tests. If you are testing multiple functions, they will not
|
341
|
+
interfere with each other as they might if they used global variables.
|
336
342
|
|
337
343
|
### Sharing resources
|
338
344
|
|
@@ -345,10 +351,10 @@ re-establishing it for every function invocation.
|
|
345
351
|
|
346
352
|
The best practice for sharing a resource across function invocations is to
|
347
353
|
initialize it in a {FunctionsFramework.on_startup} block, and reference it from
|
348
|
-
global shared data. (As discussed above,
|
349
|
-
in a startup task rather than at the top level of a Ruby file,
|
350
|
-
the Functions Framework's global data mechanism rather than Ruby's
|
351
|
-
variables.)
|
354
|
+
global shared data. (As discussed above, the best practice is to initialize
|
355
|
+
shared resources in a startup task rather than at the top level of a Ruby file,
|
356
|
+
and to use the Functions Framework's global data mechanism rather than Ruby's
|
357
|
+
global variables.)
|
352
358
|
|
353
359
|
Here is a simple example:
|
354
360
|
|
@@ -383,6 +389,48 @@ may perform CPU throttling, and therefore there may not be an opportunity for
|
|
383
389
|
cleanup tasks to run. (For example, you could register a `Kernel.at_exit` task,
|
384
390
|
but the Ruby VM may still terminate without calling it.)
|
385
391
|
|
392
|
+
### Lazy initialization
|
393
|
+
|
394
|
+
Because startup tasks run during cold start, they could have an impact on your
|
395
|
+
function's startup latency. You can mitigate this by initializing some globals
|
396
|
+
_lazily_. When setting a global, instead of computing and setting the value
|
397
|
+
directly (e.g. constructing a shared API client object directly), you can
|
398
|
+
provide a block that describes how to construct it on demand.
|
399
|
+
|
400
|
+
Here is an example using the storage client we saw above.
|
401
|
+
|
402
|
+
```ruby
|
403
|
+
require "functions_framework"
|
404
|
+
|
405
|
+
# This startup block describes _how_ to initialize a shared client, but
|
406
|
+
# does not construct it immediately.
|
407
|
+
FunctionsFramework.on_startup do
|
408
|
+
require "google/cloud/storage"
|
409
|
+
set_global :storage_client do
|
410
|
+
Google::Cloud::Storage.new
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# The first time this function is invoked, it will call the above block
|
415
|
+
# to construct the storage client. Subsequent invocations will not need
|
416
|
+
# to construct it again, but will reuse the same shared object.
|
417
|
+
FunctionsFramework.http "storage_example" do |request|
|
418
|
+
bucket = global(:storage_client).bucket "my-bucket"
|
419
|
+
file = bucket.file "path/to/my-file.txt"
|
420
|
+
file.download.to_s
|
421
|
+
end
|
422
|
+
```
|
423
|
+
|
424
|
+
The block will not be called until a function actually attempts to access the
|
425
|
+
global. From that point, subsequent accesses of the global will return that
|
426
|
+
same shared value; the block will be called at most once. This is true even if
|
427
|
+
multiple functions are run concurrently in different threads.
|
428
|
+
|
429
|
+
Lazy initialization is particularly useful if you define several different
|
430
|
+
functions that may use different sets of shared resources. Instead of
|
431
|
+
initializing all resources eagerly up front, you could initialize them lazily
|
432
|
+
and run only the code needed by the function that is actually invoked.
|
433
|
+
|
386
434
|
## Structuring a project
|
387
435
|
|
388
436
|
A Functions Framework based "project" or "application" is a typical Ruby
|
@@ -422,7 +470,7 @@ Following is a typical layout for a Functions Framework based project.
|
|
422
470
|
```ruby
|
423
471
|
# Gemfile
|
424
472
|
source "https://rubygems.org"
|
425
|
-
gem "functions_framework", "~> 0.
|
473
|
+
gem "functions_framework", "~> 0.8"
|
426
474
|
```
|
427
475
|
|
428
476
|
```ruby
|
@@ -74,7 +74,7 @@ module FunctionsFramework
|
|
74
74
|
# @param argv [Array<String>]
|
75
75
|
# @return [self]
|
76
76
|
#
|
77
|
-
def parse_args argv # rubocop:disable Metrics/MethodLength
|
77
|
+
def parse_args argv # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
78
78
|
@option_parser = ::OptionParser.new do |op| # rubocop:disable Metrics/BlockLength
|
79
79
|
op.on "-t", "--target TARGET",
|
80
80
|
"Set the name of the function to execute (defaults to #{DEFAULT_TARGET})" do |val|
|
@@ -164,6 +164,28 @@ module FunctionsFramework
|
|
164
164
|
callable.call(*args)
|
165
165
|
end
|
166
166
|
|
167
|
+
##
|
168
|
+
# A lazy evaluator for a global
|
169
|
+
# @private
|
170
|
+
#
|
171
|
+
class LazyGlobal
|
172
|
+
def initialize block
|
173
|
+
@block = block
|
174
|
+
@value = nil
|
175
|
+
@mutex = ::Mutex.new
|
176
|
+
end
|
177
|
+
|
178
|
+
def value
|
179
|
+
@mutex.synchronize do
|
180
|
+
if @block
|
181
|
+
@value = @block.call
|
182
|
+
@block = nil
|
183
|
+
end
|
184
|
+
@value
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
167
189
|
##
|
168
190
|
# A base class for a callable object that provides calling context.
|
169
191
|
#
|
@@ -196,7 +218,9 @@ module FunctionsFramework
|
|
196
218
|
# @return [Object]
|
197
219
|
#
|
198
220
|
def global key
|
199
|
-
@__globals[key]
|
221
|
+
value = @__globals[key]
|
222
|
+
value = value.value if value.is_a? LazyGlobal
|
223
|
+
value
|
200
224
|
end
|
201
225
|
|
202
226
|
##
|
@@ -204,11 +228,35 @@ module FunctionsFramework
|
|
204
228
|
# are frozen when the server starts, so this call will raise an exception
|
205
229
|
# if called from a normal function.
|
206
230
|
#
|
207
|
-
#
|
208
|
-
#
|
231
|
+
# You can set a global to a final value, or you can provide a block that
|
232
|
+
# lazily computes the global the first time it is requested.
|
233
|
+
#
|
234
|
+
# @overload set_global(key, value)
|
235
|
+
# Set the given global to the given value. For example:
|
236
|
+
#
|
237
|
+
# set_global(:project_id, "my-project-id")
|
238
|
+
#
|
239
|
+
# @param key [Symbol,String]
|
240
|
+
# @param value [Object]
|
241
|
+
# @return [self]
|
242
|
+
#
|
243
|
+
# @overload set_global(key, &block)
|
244
|
+
# Call the given block to compute the global's value only when the
|
245
|
+
# value is actually requested. This block will be called at most once,
|
246
|
+
# and its result reused for subsequent calls. For example:
|
247
|
+
#
|
248
|
+
# set_global(:connection_pool) do
|
249
|
+
# ExpensiveConnectionPool.new
|
250
|
+
# end
|
251
|
+
#
|
252
|
+
# @param key [Symbol,String]
|
253
|
+
# @param block [Proc] A block that lazily computes a value
|
254
|
+
# @yieldreturn [Object] The value
|
255
|
+
# @return [self]
|
209
256
|
#
|
210
|
-
def set_global key, value
|
211
|
-
@__globals[key] = value
|
257
|
+
def set_global key, value = nil, &block
|
258
|
+
@__globals[key] = block ? LazyGlobal.new(block) : value
|
259
|
+
self
|
212
260
|
end
|
213
261
|
|
214
262
|
##
|
@@ -49,16 +49,19 @@ module FunctionsFramework
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def normalized_context input
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
service, resource = analyze_resource raw_context&.[]("resource") || input["resource"]
|
52
|
+
id = normalized_context_field input, "eventId"
|
53
|
+
timestamp = normalized_context_field input, "timestamp"
|
54
|
+
type = normalized_context_field input, "eventType"
|
55
|
+
service, resource = analyze_resource normalized_context_field input, "resource"
|
57
56
|
service ||= service_from_type type
|
58
57
|
return nil unless id && timestamp && type && service && resource
|
59
58
|
{ id: id, timestamp: timestamp, type: type, service: service, resource: resource }
|
60
59
|
end
|
61
60
|
|
61
|
+
def normalized_context_field input, field
|
62
|
+
input["context"]&.[](field) || input[field]
|
63
|
+
end
|
64
|
+
|
62
65
|
def analyze_resource raw_resource
|
63
66
|
service = resource = nil
|
64
67
|
case raw_resource
|
@@ -158,7 +158,7 @@ module FunctionsFramework
|
|
158
158
|
::Signal.trap "SIGHUP" do
|
159
159
|
Server.signal_enqueue "SIGHUP", @config.logger, @server
|
160
160
|
end
|
161
|
-
rescue ::ArgumentError
|
161
|
+
rescue ::ArgumentError
|
162
162
|
# Not available on all systems
|
163
163
|
end
|
164
164
|
@signals_installed = true
|
@@ -366,9 +366,10 @@ module FunctionsFramework
|
|
366
366
|
::Rack::RACK_ERRORS => ::StringIO.new
|
367
367
|
}
|
368
368
|
headers.each do |header|
|
369
|
-
|
369
|
+
case header
|
370
|
+
when String
|
370
371
|
name, value = header.split ":"
|
371
|
-
|
372
|
+
when ::Array
|
372
373
|
name, value = header
|
373
374
|
end
|
374
375
|
next unless name && value
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: functions_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cloud_events
|
@@ -87,10 +87,10 @@ homepage: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
|
87
87
|
licenses:
|
88
88
|
- Apache-2.0
|
89
89
|
metadata:
|
90
|
-
changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.
|
90
|
+
changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.8.0/file.CHANGELOG.html
|
91
91
|
source_code_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
92
92
|
bug_tracker_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues
|
93
|
-
documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.
|
93
|
+
documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.8.0
|
94
94
|
post_install_message:
|
95
95
|
rdoc_options: []
|
96
96
|
require_paths:
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
- !ruby/object:Gem::Version
|
107
107
|
version: '0'
|
108
108
|
requirements: []
|
109
|
-
rubygems_version: 3.
|
109
|
+
rubygems_version: 3.2.11
|
110
110
|
signing_key:
|
111
111
|
specification_version: 4
|
112
112
|
summary: Functions Framework for Ruby
|