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:
committed by
Ta-Ching Chen
parent
f104f0b46b
commit
c717f182b6
@@ -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"]
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "rack"
|
||||
gem "thin"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Executable
+9
@@ -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}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
||||
|
||||
gem "nokogiri"
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user