functions_framework 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|