From Ruby to Elixir



From Ruby to Elixir

0 0


ruby_to_elixir

Presentation about our journey from Ruby to Elixir

On Github shiroyasha / ruby_to_elixir

From Ruby to Elixir

I am Igor

I write software

with some AWESOME people

Semaphore

a hosted CI service

When you Push, we Build

When you Merge, we Deploy

Processing 100k jobs daily

On more than 100k virtual machines

errors are not an option

but they will happen

we must be resilient

This talk

  • Semaphore and Ruby
  • Why Elixir?
  • Elixir in practice

We ❤ Ruby

Used it for 8 years at Rendered Text

We use Rails & Sinatra

Capistrano for deployment

Chef for provisioning

Sidekiq for background jobs

RSpec & Cucumber for testing

Postgres, Redis, Rabbit...

Ruby has superb tools

an awesome community

treats us like human beings

so what happened?

Sidekiq died

often

we wrapped it into upstart scripts

hard to test

slow restarts

uses too much memory

if you want

Multiple sidekiq processes

you will have complicated upstart scripts

sidekiq can use up a lot of resources

You need Inspeqtor

Another issue

Parallel job creation

Serial job request creation

class Build < ActiveRecord::Base
  has_many :jobs
end
build.jobs.map do |job|
  create_job_request(job)
end

Let's use pmap

build.jobs.pmap do |job|
  create_job_request(job)
end

What we wanted

it was time to change something

02. Why Elixir?

we need something that is

fun

fast

fault tolerant

has cheap threads

Erlang is an obvious choice

but then we found Elixir

we fell in love

based on the

battle tested Erlang VM

Pure functional language

[1, 2, 3, 4, 5, 6]
|> Enum.filter(&Integer.is_odd/1)
|> Enum.map(&(&1 * &1))
@log_levels [ :info, :trace, :error, :warning ]

@log_levels |> Enum.map fn level ->
  def unquote(level)(string) do
    IO.puts "[#{level}] #{message}"
  end
end

has macros

has agents

defmodule Stack do
  def start_link do
    Agent.start_link fn -> [] end
  end

  def push(pid, item) do
    Agent.update pid, fn(stack) -> [item | stack] end
  end

  def pop(pid) do
    Agent.get_and_update pid, fn [item | last] -> {item, last} end
  end
end

feels like Ruby

03. Elixir in practice

every new microservice

written in Elixir

we used to measure response time

in miliseconds

now we measure

microseconds

Supervisors

the most awesome thing, ever

the basis of fault tolerance

replaced our upstart scripts

supervisors are easily testable

Deployment

is trivial

compile a binary package deploy a .tar.gz package that's all

Ruby projects can be Dockerized

but the images are gigantic

on the other hand

Elixir and Docker

are a dream team

Downsides of Elixir?

there are a few

fewer out-of-box solutions

pagination, metrics, logs...

you sometimes need to fork & improve

App configuration

is static, weird, and sometimes feels broken

we want configuration via

environment variables

Takeaways from this talk

If you have troubles with

stability or scalability

Elixir is an awesome

replacement for your Ruby based services

also, try out

Phoenix & Ecto

a.k.a Rails in the Elixir world

Questions?

follow @igor_sarcevic & check out semaphoreci.com

From Ruby to Elixir