Levee – A Whirlwind Tour



Levee – A Whirlwind Tour

0 0


Talks.Levee.A-Whirlwind-Tour

Slides and code samples for a talk on Levee

On Github cablehead / Talks.Levee.A-Whirlwind-Tour

Levee

A Whirlwind Tour

Andy Gayton / @cablelounger

Levee is a tool to succinctly and quickly create high performance network appliances.

Here's how it looks

local levee = require("levee")

local h = levee.Hub()

local err, serve = h.tcp:listen(9000)

for conn in serve do
  h:spawn(function()
    while true do
      local err = conn:write("Hello World\n")
      if err then break end
      h:sleep(1000)
    end
    conn:close()
  end)
end

Major features

  • Straight forward concurrency
  • Build standalone static binaries
  • Performance
  • Single and Zero-copy networking
    • e.g. Streaming JSON + Msgpack decoding, Splice, Tee
  • Built-in Testing

Why Lua

  • Built-in collaborative coroutines (Green threads)
  • Tiny, easy to embed, (NGINX, Redis)
  • LuaJIT
  • Great FFI -- C.sleep(1)

Great FFI


local pid = C.getpid()
C.kill(pid, C.SIGHUP)


Similar projects

  • Luvit
  • Implements the same APIs as Node.js, but in Lua!
  • WHY??
  • 'If you start with that sort of slogan there's no where you can go.'
  • also: libuv
  • We don't love it

Callback hell

Swiss army knife

  • TCP
  • HTTP
  • File IO
  • Processes
  • Threads
  • Signals
  • Consul

Chat relay

local err, serve = h.tcp:listen(9000, "0.0.0.0")

local connections = {}

for conn in serve do
  h:spawn(function()
    connections[conn.no] = conn
    local stream = conn:stream()
    while true do
      local err, line = stream:line("\r\n")
      if err then break end
      for __, item in pairs(connections) do
        item:write(line.."\n")
      end
    end
    conn:close()
    connections[conn.no] = nil
  end)
end

Project layout

./demo
./demo/main.lua
./demo/sedaas.lua
./tests
./tests/test_sedaas.lua

demo/sedaas.lua

Sed as a service

return function(h)
  local child = h.process:spawn(
    "sed", {argv={"-l", "s/trump/orange pumpkin head/g"}})

  local stream = child.stdout:stream()

  return function(s)
    child.stdin:send(s.."\n")
    local err, line = stream:line()
    return line
  end
end

tests/test_sedaas.lua

local levee = require("levee")
local Sedaas = require("demo.sedaas")


return {
  test_core = function()
    local h = levee.Hub()
    local sedaas = Sedaas(h)
    assert.equal(sedaas("foo"), "foo")
    assert.equal(sedaas("trump card"), "orange pumpkin head card")
  end,
}

levee test

Add Sedaas to our chat relay

      while true do
        local err, line = stream:line("\r\n")
        if err then break end

        line = sedaas(line)

        for __, item in pairs(connections) do
          item:write(line.."\n")
        end
      end

HTTP endpoint

Metrics; whose connected?

  local count = 0

  local err, drop = h.http:droplet(8000, "0.0.0.0")

  drop:route("/", function(h, req)
    return ("connected: %s"):format(count)
  end)

HTTP Endpoint

    h:spawn(function()
      connections[conn.no] = conn
      count = count + 1
      local stream = conn:stream()
      while true do
        local err, line = stream:line("\r\n")
        if err then break end
        line = sedaas(line)
        for __, item in pairs(connections) do
          item:write(line.."\n")
        end
      end
      conn:close()
      count = count - 1
      connections[conn.no] = nil
    end)

levee build

Major features

  • Straight forward concurrency
  • Build standalone static binaries
  • Performance
  • Single and Zero-copy networking
    • e.g. Streaming JSON + Msgpack decoding, Splice, Tee
  • Built-in Testing

Swiss army knife

  • TCP
  • HTTP
  • File IO
  • Processes
  • Threads
  • Signals
  • Consul

Try it out

brew install imgix/brew/levee

source / github

these slides and samples / github

THE END

Levee A Whirlwind Tour Andy Gayton / @cablelounger