Added support for Ruby v2 Specialization (#1101)

* Added support for Ruby v2 Specialization
* Added ruby v2 example with builder code
This commit is contained in:
Brendan Stennett
2019-03-13 22:55:26 +08:00
committed by Ta-Ching Chen
parent f104f0b46b
commit c717f182b6
12 changed files with 153 additions and 19 deletions
+5 -10
View File
@@ -1,16 +1,11 @@
FROM ruby:2.4.1
FROM ruby:2.6.1-alpine3.9
RUN apt-get update -qq && apt-get install -y build-essential
RUN mkdir /app
WORKDIR /app
ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
RUN bundle install
RUN apk update
RUN apk add --no-cache build-base
COPY . /app
EXPOSE 8888
WORKDIR /app
RUN bundle install
ENTRYPOINT ["ruby"]
CMD ["server.rb"]
+1
View File
@@ -2,3 +2,4 @@
source "https://rubygems.org"
gem "rack"
gem "thin"
+1 -1
View File
@@ -2,7 +2,7 @@
This is the Ruby environment for Fission.
It's a Docker image containing a Ruby 2.4.1 runtime. The image uses
It's a Docker image containing a Ruby 2.6.1 runtime. The image uses
Rack with WEBrick to host the internal web server.
The environment works via convention where you create a Ruby method
+12
View File
@@ -0,0 +1,12 @@
ARG BUILDER_IMAGE=fission/builder:latest
FROM ${BUILDER_IMAGE}
FROM ruby:2.6.1-alpine3.9
COPY --from=0 /builder /builder
RUN apk update
RUN apk add --no-cache ruby ruby-dev ruby-bundler build-base
ADD defaultBuildCmd /usr/local/bin/build
EXPOSE 8001
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
set -euxo pipefail
if [ -f ${SRC_PKG}/Gemfile.lock ]
then
cd $SRC_PKG
bundle install --deployment
fi
cp -r ${SRC_PKG} ${DEPLOY_PKG}
+3 -3
View File
@@ -7,10 +7,10 @@ module Fission
def self.call(env)
context = Context.new(env)
response = if method(:handler).arity > 0
handler(context)
response = if $handler.arity > 0
$handler.call(context)
else
handler
$handler.call
end
response.is_a?(Array) ? response : Rack::Response.new([response]).finish
+65 -3
View File
@@ -1,10 +1,13 @@
# frozen_string_literal: true
require 'benchmark'
require 'json'
module Fission
CODE_PATH = '/userfunc/user'
module Specializer
CODE_PATH = '/userfunc/user'
def self.call(env)
request = Request.new(env)
@@ -12,11 +15,70 @@ module Fission
time = Benchmark.measure { load CODE_PATH }
request.logger.info("User code loaded in #{(time.real * 1000).round(3)}ms")
Rack::Response.new([], 201).finish
# set to "handler" for v1 specialization
$handler = method(:handler)
Rack::Response.new([], 201).finish
rescue => e
request.logger.error(%(Specialization failed - #{e}\n#{e.backtrace.join("\n")}))
Rack::Response.new(['500 Internal Server Error'], 500, {}).finish
end
end
module V2
module Specializer
def self.load_vendor(path)
gems = Dir[File.join(path, 'vendor/bundle/ruby/*/gems/*/lib')]
exts = Dir[File.join(path, 'vendor/bundle/ruby/*/extensions/x86_64-linux/*/*')]
$LOAD_PATH.unshift(*gems)
$LOAD_PATH.unshift(*exts)
end
def self.call(env)
request = Request.new(env)
body = JSON.parse(request.body.read)
path = body['filepath']
func = body['functionName']
time = Benchmark.measure do
if File.file?(path)
# If pointing to just a single file, all we need to do is load it
request.logger.debug("Loading file #{path}")
load path
elsif File.directory?(path)
# First we want to load all the vendor files
load_vendor(path)
# We then want to get all the .rb files in this src
rb_files = File.join(path, "**/*.rb")
# But we don't want to include the vendor files that we loaded above
vendor_dir = File.join(path, 'vendor')
src_files = Dir[rb_files].reject {|d| d.start_with?(vendor_dir) }
request.logger.debug("Loading sources #{src_files}")
src_files.each do |file|
load file
end
else
request.logger.error(%(Specialization failed - could not find src at #{path}}))
Rack::Response.new(['500 Internal Server Error'], 500, {}).finish
return
end
end
request.logger.info("User code loaded in #{(time.real * 1000).round(3)}ms")
# set global handler for this specialization
$handler = method(func)
Rack::Response.new([], 201).finish
end
end
end
end
+14 -2
View File
@@ -1,21 +1,33 @@
# frozen_string_literal: true
require 'rack'
require 'thin'
require 'logger'
require_relative 'fission/specializer'
require_relative 'fission/handler'
$handler = nil
app = Rack::Builder.new do
use Rack::Logger, Logger::DEBUG
use Rack::CommonLogger
map "/specialize" do
run Fission::Specializer
end
map "/" do
map '/v2/specialize' do
run Fission::V2::Specializer
end
map "/healthz" do
run ->(env) { [ 200, {}, [] ] }
end
map '/' do
run Fission::Handler
end
end
Rack::Handler::WEBrick.run app, Host: '0.0.0.0', Port: 8888
Rack::Handler::Thin.run app, Host: '0.0.0.0', Port: 8888
+8
View File
@@ -105,3 +105,11 @@ $ curl http://$FISSION_ROUTER/request/123?key=abc
--BODY--
```
## V2 Specification Example (with builder support)
```
$ fission function create --name parse --env ruby --src "parse/*" --entrypoint handler
$ fission fn test --name parse --body '<message>This is my message</message>'
This is my message
```
+7
View File
@@ -0,0 +1,7 @@
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "nokogiri"
+15
View File
@@ -0,0 +1,15 @@
GEM
remote: https://rubygems.org/
specs:
mini_portile2 (2.4.0)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
PLATFORMS
ruby
DEPENDENCIES
nokogiri
BUNDLED WITH
1.16.1
+13
View File
@@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'nokogiri'
def handler(context)
context.logger.info("Received request")
doc = Nokogiri::XML(context.request.body.read)
ele = doc.at_xpath('//message')
msg = ele.nil? ? 'No Message' : ele.content
Rack::Response.new([msg, "\n"]).finish
end