Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Everything a Microservice: The Worst Possible I...

Kevin Kuchta
December 22, 2022

Everything a Microservice: The Worst Possible Intro to Druby

Microservices are great, but I think we can all agree: we need more of them and they should be micro-er. What's the logical limit here? What if every object was remote in a language where everything's an object? Let's take a look at dRuby, the distributed programming module you've never heard of, and use it to achieve that deranged goal! You'll learn about a nifty little corner of the standard library while we attempt to reach the illogical conclusion of today's hottest architecture trend. Be warned: those sitting in the first few rows may get poorly-marshaled data on them.

Kevin Kuchta

December 22, 2022
Tweet

More Decks by Kevin Kuchta

Other Decks in Programming

Transcript

  1. @[email protected] / @kkuchta Microservices What do we know A. Regular

    services, but smaller B. Better than services
  2. @[email protected] / @kkuchta Microservices What do we know A. Regular

    services, but smaller B. Better than services C. Smaller = better
  3. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts "hi" end end obj = SomeClass.new local.rb remote.rb
  4. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts "hi" end end obj = SomeClass.new obj.foo local.rb remote.rb
  5. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts "hi" end end obj = SomeClass.new obj.foo local.rb remote.rb # puts "hi" on remote server
  6. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo local.rb remote.rb
  7. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote local.rb remote.rb
  8. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote local.rb remote.rb
  9. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote local.rb remote.rb
  10. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote local.rb remote.rb
  11. @[email protected] / @kkuchta Microservices Every goddamn object local.rb remote.rb class

    SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  12. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end
  13. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service(
  14. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555',
  15. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new )
  16. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  17. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  18. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' remote = DRbObject.new_with_uri( require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  19. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' remote = DRbObject.new_with_uri( 'druby://localhost:5555' ) require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  20. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' remote = DRbObject.new_with_uri( 'druby://localhost:5555' ) remote.foo require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  21. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' remote = DRbObject.new_with_uri( 'druby://localhost:5555' ) remote.foo require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  22. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb $

    ruby remote.rb require 'drb/drb' remote = DRbObject.new_with_uri( 'druby://localhost:5555' ) remote.foo require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  23. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb $

    ruby local.rb $ ruby remote.rb require 'drb/drb' remote = DRbObject.new_with_uri( 'druby://localhost:5555' ) remote.foo require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  24. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb $

    ruby local.rb $ $ ruby remote.rb foo ran here require 'drb/drb' remote = DRbObject.new_with_uri( 'druby://localhost:5555' ) remote.foo require 'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end DRb.start_service( 'druby://localhost:5555', RemoteServer.new ) DRb.thread.join
  25. @[email protected] / @kkuchta Creating Remote Objects automagic local.rb remote.rb class

    SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo
  26. @[email protected] / @kkuchta Remote Objects automagic local.rb remote.rb class SomeClass

    def foo; end end object = remote_new(SomeClass) object.foo
  27. @[email protected] / @kkuchta Remote Objects automagic *magic* local.rb remote.rb class

    SomeClass def foo; end end object = remote_new(SomeClass) object.foo
  28. @[email protected] / @kkuchta Remote Objects automatic local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() end end DRb.start_service( 'druby://localhost:5555', RemoteNewer.new) class SomeClass # ... end object = remote_new(SomeClass)
  29. @[email protected] / @kkuchta Remote Objects automagic local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() end end DRb.start_service( 'druby://localhost:5555', RemoteNewer.new) class SomeClass # ... end r = DRbObject.new_with_uri( 'druby://localhost:5555' ) r.make_new(SomeClass)
  30. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteObject

    def foo "bar" end end result = remote.foo result.class # string
  31. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteObject

    def foo SomethingWeird.new end end result = remote.foo result.class # Drb::DrbObject
  32. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteObject

    def foo SomethingWeird.new end end result = remote.foo result.class # Drb::DrbObject result.something()
  33. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteObject

    def foo SomethingWeird.new end end result = remote.foo result.class # Drb::DrbObject result.something() # ^ proxies method call
  34. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end
  35. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end class SomeClass # ... end
  36. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end class SomeClass # ... end r = DRbObject.new_with_uri( 'druby://localhost:5555' )
  37. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end class SomeClass # ... end r = DRbObject.new_with_uri( 'druby://localhost:5555' ) obj = r.make_new(SomeClass)
  38. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end class SomeClass # ... end r = DRbObject.new_with_uri( 'druby://localhost:5555' ) obj = r.make_new(SomeClass) obj.class # DRb::DRbObject
  39. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end
  40. @[email protected] / @kkuchta Remote Objects new + newer local.rb remote.rb

    class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUndumped) end end
  41. @[email protected] / @kkuchta Remote Objects local.rb remote.rb class RemoteNewer def

    make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUndumped) end end
  42. @[email protected] / @kkuchta Remote Objects putting it together local.rb remote.rb

    class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUn dumped) end end
  43. @[email protected] / @kkuchta Remote Objects putting it together local.rb remote.rb

    class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUn dumped) end end r = DRbObject.new_with_uri( 'druby://localhost:5555')
  44. @[email protected] / @kkuchta Remote Objects putting it together local.rb remote.rb

    class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUn dumped) end end r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123")
  45. @[email protected] / @kkuchta Remote Objects putting it together local.rb remote.rb

    class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUn dumped) end end r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123") remote_str.class # Drb::DrbObject
  46. @[email protected] / @kkuchta Remote Objects putting it together local.rb remote.rb

    class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass .new(*rest, **kwargs, &block) .extend(DRb::DRbUn dumped) end end r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123") remote_str.class # Drb::DrbObject remote_str.to_i
  47. @[email protected] / @kkuchta Logging Remote Objects it's login' time local.rb

    remote.rb module InvokeMethodWithLogging def perform result = super @msg_id && ( puts "remote: #{@msg_id}" ) result end end class DRb::DRbServer::InvokeMethod prepend InvokeMethodWithLogging end
  48. @[email protected] / @kkuchta Logging Remote Objects it's login' time local.rb

    remote.rb module InvokeMethodWithLogging def perform result = super @msg_id && ( puts "remote: #{@msg_id}" ) result end end class DRb::DRbServer::InvokeMethod prepend InvokeMethodWithLogging end
  49. @[email protected] / @kkuchta class RemoteNewer def make_new(klass, *rest, **kwargs, &block)

    obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRbUnd umped) end end Remote Objects it's log-o-clock local.rb remote.rb r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123") remote_str.class # Drb::DrbObject remote_str.to_i
  50. @[email protected] / @kkuchta class RemoteNewer def make_new(klass, *rest, **kwargs, &block)

    obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRbUnd umped) end end Remote Objects it's log-o-clock local.rb remote.rb $ remote.rb r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123") remote_str.class # Drb::DrbObject remote_str.to_i
  51. @[email protected] / @kkuchta class RemoteNewer def make_new(klass, *rest, **kwargs, &block)

    obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRbUnd umped) end end Remote Objects it's log-o-clock local.rb remote.rb $ remote.rb remote: make_new r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123") remote_str.class # Drb::DrbObject remote_str.to_i
  52. @[email protected] / @kkuchta class RemoteNewer def make_new(klass, *rest, **kwargs, &block)

    obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRbUnd umped) end end Remote Objects it's log-o-clock local.rb remote.rb $ remote.rb remote: make_new remote: to_i r = DRbObject.new_with_uri( 'druby://localhost:5555') remote_str = r.make_new( String, "123") remote_str.class # Drb::DrbObject remote_str.to_i
  53. @[email protected] / @kkuchta Remote Objects Remote Object Everywhere local.rb remote.rb

    remote = DRbObject .new_with_uri('druby://localhost:5555')
  54. @[email protected] / @kkuchta Remote Objects Remote Object Everywhere local.rb remote.rb

    remote = DRbObject .new_with_uri('druby://localhost:5555') some_string = remote .make_new(String, "123")
  55. @[email protected] / @kkuchta Remote Objects Remote Object Everywhere local.rb remote.rb

    remote = DRbObject .new_with_uri('druby://localhost:5555') some_string = remote .make_new(String, "123") some_hash = remote .make_new(Hash)
  56. @[email protected] / @kkuchta Remote Objects Remote Object Everywhere local.rb remote.rb

    remote = DRbObject .new_with_uri('druby://localhost:5555') some_string = remote .make_new(String, "123") some_hash = remote .make_new(Hash) some_other = remote .make_new(Other, 'foo', 3)
  57. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRb Undumped) end end some_string = String.new("foo")
  58. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRb Undumped) end end some_string = String.new("foo") $r = DRbObject.new_with_uri( 'druby://localhost:5555') class Object def self.new(*args, **kwargs, &block) $r.remote_new( self, *args, **kwargs, &block) end end
  59. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRb Undumped) end end some_string = String.new("foo") $r = DRbObject.new_with_uri( 'druby://localhost:5555') class Object def self.new(*args, **kwargs, &block) $r.remote_new( self, *args, **kwargs, &block) end end
  60. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class RemoteNewer def make_new(klass, *rest, **kwargs, &block) obj = klass.new(*rest, **kwargs, &block).extend(DRb::DRb Undumped) end end some_string = String.new("foo") $r = DRbObject.new_with_uri( 'druby://localhost:5555') class Object def self.new(*args, **kwargs, &block) $r.remote_new( self, *args, **kwargs, &block) end end
  61. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class Object def self.new(*args, **kwargs, &block) contains_recursion = caller.any? { _1 =~ /(drb\/drb)/ } end end end
  62. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class Object @@old_new = method(:new) def self.new(*args, **kwargs, &block) contains_recursion = caller.any? { _1 =~ /(drb\/drb)/ } end end end
  63. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class Object @@old_new = method(:new) def self.new(*args, **kwargs, &block) contains_recursion = caller.any? { _1 =~ /(drb\/drb)/ } if contains_recursion @@old_new.unbind.bind(self)[*args, **kwargs, &block] end end end
  64. @[email protected] / @kkuchta Magic New what could go wrong? local.rb

    remote.rb class Object @@old_new = method(:new) def self.new(*args, **kwargs, &block) contains_recursion = caller.any? { _1 =~ /(drb\/drb)/ } if contains_recursion @@old_new.unbind.bind(self)[*args, **kwargs, &block] else $r.make_new(self, *args, **kwargs, &block) end end end
  65. @[email protected] / @kkuchta Magic New it works! local.rb remote.rb some_string

    = String.new("foo") some_string.to_i arr = Array.new([1,2,3]) sum = arr.sum
  66. @[email protected] / @kkuchta Magic New it works! local.rb remote.rb $

    remote.rb remote: make_new remote: to_i remote: make_new remote: sum some_string = String.new("foo") some_string.to_i arr = Array.new([1,2,3]) sum = arr.sum
  67. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) sum = arr.sum arr.include?(2) arr.join("foo")
  68. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) sum = arr.sum arr.include?(2) arr.join("foo") arr.each { |i| puts i }
  69. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) sum = arr.sum arr.include?(2) arr.join("foo") arr.each { |i| puts i }
  70. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) sum = arr.sum arr.include?(2) arr.join("foo") arr.each { |i| puts i }
  71. @[email protected] / @kkuchta Microservices friggin' procs some_remote_object.foo(arg1) # Under the

    hood: Marshal.dump(arg1) some_remote_object.foo { |x| x + 1 } # Under the hood: Marshal.dump(proc { |x| x + 1 })
  72. @[email protected] / @kkuchta Microservices friggin' procs > dumped = Marshal.dump({a:

    1}) => "\x04\b{\x06:\x06ai\x06" > Marshal.load(dumped) => {:a=>1}
  73. @[email protected] / @kkuchta Microservices friggin' procs Marshal.dump(proc { |x| x

    + 1 }) # TypeError: no _dump_data is # defined for class Proc
  74. @[email protected] / @kkuchta Microservices friggin' procs y = 3 Marshal.dump(proc

    { |x| x + y }) # TypeError: no _dump_data is # defined for class Proc
  75. @[email protected] / @kkuchta def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc

    ' + a_proc_string) end Microservices friggin' procs class Proc end "{ |x| x + 1 }"
  76. @[email protected] / @kkuchta def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc

    ' + a_proc_string) end Microservices friggin' procs class Proc end "{ |x| x + 1 }" eval "proc { |x| x + 1 }"
  77. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block some_proc = proc do |x| x + 1 end some_proc.binding.source_location
  78. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block some_proc = proc do |x| x + 1 end some_proc.binding.source_location # ["some_filename.rb", 1]
  79. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block require 'method_source' some_proc = proc do |x| x + 1 end
  80. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block require 'method_source' some_proc = proc do |x| x + 1 end puts some_proc.source # "some_proc = proc do |x| # x + 1 # end"
  81. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with SyntaxTree class BlockFinder < SyntaxTree::Visitor attr_reader :first_block visit_method def visit_do_block(node) @first_block ||= node end visit_method def visit_brace_block(node) @first_block ||= node end end def serialize_block(&block) source = block.source root = SyntaxTree.parse(source) visitor = BlockFinder.new visitor.visit(root) block_node = visitor.first_block formatter = SyntaxTree::Formatter.new(source, [], 80) formatter.instance_variable_set(:@stack, [proc {SyntaxTree::Program.new(statements: [], location: nil)}]) formatter.format(block_node) formatter.flush formatter.output.join end
  82. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem "some_proc = proc { |x| x + 1 }"
  83. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  84. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  85. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  86. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  87. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  88. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  89. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }"
  90. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem = some_proc proc proc() {} |x| + x 1 "some_proc = proc { |x| x + 1 }" "{ |x| x + 1 }"
  91. @[email protected] / @kkuchta Microservices friggin' procs class Proc def _dump(depth)

    serialize_block(&self) end def self._load(a_proc_string) eval('proc ' + a_proc_string) end end
  92. @[email protected] / @kkuchta Microservices friggin' procs dumped = Marshal.dump(proc {

    |x| x + 1 }) class Proc def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc ' + a_proc_string) end end
  93. @[email protected] / @kkuchta Microservices friggin' procs dumped = Marshal.dump(proc {

    |x| x + 1 }) # "\x04\bIu:\tProc\x13 { |x| x + 1 }\x06:\x06ET" class Proc def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc ' + a_proc_string) end end
  94. @[email protected] / @kkuchta Microservices friggin' procs dumped = Marshal.dump(proc {

    |x| x + 1 }) # "\x04\bIu:\tProc\x13 { |x| x + 1 }\x06:\x06ET" reloaded_proc = Marshal.load(dumped) class Proc def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc ' + a_proc_string) end end
  95. @[email protected] / @kkuchta Microservices friggin' procs dumped = Marshal.dump(proc {

    |x| x + 1 }) # "\x04\bIu:\tProc\x13 { |x| x + 1 }\x06:\x06ET" reloaded_proc = Marshal.load(dumped) puts reloaded_proc[ 3 ] # prints 4! class Proc def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc ' + a_proc_string) end end
  96. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb $ remote.rb

    remote: make_new 1 2 3 remote: each arr = Array.new([1,2,3]) arr.each { |i| puts i }
  97. @[email protected] / @kkuchta Microservices literally the worst class Array def

    self.new puts "new called" end end Array.new # "new called"
  98. @[email protected] / @kkuchta Microservices literally the worst class Array def

    self.new puts "new called" end end Array.new # "new called" [1,2,3] # nothing
  99. @[email protected] / @kkuchta Microservices literally the worst puts "hi" puts

    DATA.read() __END__ hello there, world, how are you?
  100. @[email protected] / @kkuchta Microservices literally the worst puts "hi" puts

    DATA.read() __END__ hello there, world, how are you? # prints: "hello there, world, how are you?"
  101. @[email protected] / @kkuchta Microservices literally the worst eval( DATA.read .gsub(/\[(.*)\]/,

    'Array.new([\1])') ) __END__ arr = [1,2,3] # converts to Array.new([1,2,3])
  102. @[email protected] / @kkuchta Microservices literally the worst eval(DATA.read .gsub(/\[(.*)\]/, 'Array.new([\1])')

    .gsub(/{([^|]+:[^|]+)}/, 'Hash.new.merge!({\1})') .gsub(/"(.*)"/, 'String.new("\1")')) __END__ arr = [1,2,3] hash = {a: 1, b: 2} str = "whatever"
  103. @[email protected] / @kkuchta Peak Architecture more distributed def lambda_handler(event:, context:)

    DRb.start_service( "druby://localhost:5555", RemoteNewer.new ) DRb.thread.join end
  104. @[email protected] / @kkuchta Peak Architecture more distributed def lambda_handler(event:, context:)

    DRb.start_service( "druby://localhost:5555", RemoteNewer.new ) DRb.thread.join end
  105. @[email protected] / @kkuchta Peak Architecture more distributed def lambda_handler(event:, context:)

    DRb.start_service( "druby://localhost:5555", RemoteNewer.new ) DRb.thread.join end
  106. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end
  107. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda()
  108. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda() sleep 3
  109. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda() sleep 3 uri = "druby://#{lambda_hostname}:5555"
  110. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda() sleep 3 uri = "druby://#{lambda_hostname}:5555" remote_newer = DRbObject.new_with_uri(uri)
  111. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda() sleep 3 uri = "druby://#{lambda_hostname}:5555" remote_newer = DRbObject.new_with_uri(uri) new_obj = remote_newer.make_new( self, *args, **kwargs, &block)
  112. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda() sleep 3 uri = "druby://#{lambda_hostname}:5555" remote_newer = DRbObject.new_with_uri(uri) new_obj = remote_newer.make_new( self, *args, **kwargs, &block) new_obj.instance_variable_set(:@uri, uri)
  113. @[email protected] / @kkuchta Peak Architecture more distributed local.rb remote.rb class

    Object # ... def self.remote_new(*args, **kwargs, &block) end end lambda_hostname = start_lambda() sleep 3 uri = "druby://#{lambda_hostname}:5555" remote_newer = DRbObject.new_with_uri(uri) new_obj = remote_newer.make_new( self, *args, **kwargs, &block) new_obj.instance_variable_set(:@uri, uri) new_obj
  114. @[email protected] / @kkuchta Microservices Every goddamn object local.rb remote.rb class

    SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  115. @[email protected] / @kkuchta Microservices Every goddamn object 1. Preprocess all

    literals with regexes into .new calls eval(DATA.read .gsub( /\[(.*)\]/, 'Array.new([\1])') .gsub( /{([^|]+:[^|]+)}/, 'Hash.new.merge!({\1})') .gsub( /"(.*)"/, 'String.new("\1")')) __END__ arr = [1,2,3] hash = {a: 1, b: 2} str = "whatever"
  116. @[email protected] / @kkuchta Microservices Every goddamn object 1. Preprocess all

    literals with regexes into .new calls 2. Overide Object.new 3. Inspect the call stack to prevent stack over f lows class Object @@old_new = method(:new) def self.new(*args, **kwargs, &block) contains_recursion = caller .any? { _1 =~ /(drb\/drb)/ } if contains_recursion @@old_new.unbind .bind(self)[*args, **kwargs, &block] else $r.make_new(self, *args, **kwargs, &block) end end end
  117. @[email protected] / @kkuchta Microservices Every goddamn object 1. Preprocess all

    literals with regexes into .new calls 2. Overide Object.new 3. Inspect the call stack to prevent stack over f lows 4. Use Druby to create remote proxy objects # local.rb uri = "druby://#{lambda_hostname}:5555" remote_newer = DRbObject.new_with_uri(uri) new_obj = remote_newer .make_new(self, *args, **kwargs, &block) # remote.rb DRb.start_service("druby://localhost:5555", RemoteRunner.new) DRb.thread.join
  118. @[email protected] / @kkuchta Microservices Every goddamn object 1. Preprocess all

    literals with regexes into .new calls 2. Overide Object.new 3. Inspect the call stack to prevent stack over f lows 4. Use Druby to create remote proxy objects 5. Parse the AST from your own source to serialize procs class Proc def _dump(depth) serialize_block(&self) end def self._load(a_proc_string) eval('proc ' + a_proc_string) end end
  119. @[email protected] / @kkuchta Microservices Every goddamn object 1. Preprocess all

    literals with regexes into .new calls 2. Overide Object.new 3. Inspect the call stack to prevent stack over f lows 4. Use Druby to create remote proxy objects 5. Parse the AST from your own source to serialize procs 6. Run the remote server in a lambda def lambda_handler(event:, context:) DRb.start_service( "druby://localhost:5555", RemoteRunner.new) DRb.thread.join end
  120. @[email protected] / @kkuchta Microservices Every goddamn object 1. Preprocess all

    literals with regexes into .new calls 2. Overide Object.new 3. Inspect the call stack to prevent stack over f lows 4. Use Druby to create remote proxy objects 5. Parse the AST from your own source to serialize procs 6. Run the remote server in a lambda 7. MICROSERVICES! def lambda_handler(event:, context:) DRb.start_service( "druby://localhost:5555", RemoteRunner.new) DRb.thread.join end
  121. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo local.rb remote.rb
  122. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote local.rb remote.rb
  123. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote local.rb remote.rb
  124. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote local.rb remote.rb
  125. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

    foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote local.rb remote.rb
  126. @[email protected] / @kkuchta # local.rb: arr = [1,2,3] str =

    "whatever" puts arr.map { |x| x * 2} str.each_char { |c| puts c }
  127. @[email protected] / @kkuchta $ time ruby local.rb > /dev/null 0.98s

    user 0.23s system 12% cpu 9.803 total # local.rb: arr = [1,2,3] str = "whatever" puts arr.map { |x| x * 2} str.each_char { |c| puts c }
  128. @[email protected] / @kkuchta Microservices Every goddamn object Q&A class SomeClass

    def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  129. @[email protected] / @kkuchta Microservices Every goddamn object FAQ class SomeClass

    def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  130. @[email protected] / @kkuchta Microservices Every goddamn object Q: Should I

    use this in production? FAQ class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  131. @[email protected] / @kkuchta Microservices Every goddamn object Q: Should I

    use this in production? A: De f initely! FAQ class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  132. @[email protected] / @kkuchta Microservices Every goddamn object Q: Should I

    use this in production? A: De f initely! FAQ Q: What's a good use for druby for? class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  133. @[email protected] / @kkuchta Microservices Every goddamn object Q: Should I

    use this in production? A: De f initely! FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  134. @[email protected] / @kkuchta Microservices Every goddamn object Q: Where can

    I see this code in more detail? Q: Should I use this in production? A: De f initely! FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  135. @[email protected] / @kkuchta Microservices Every goddamn object Q: Where can

    I see this code in more detail? A: github.com/kkuchta/druby Q: Should I use this in production? A: De f initely! FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  136. @[email protected] / @kkuchta Microservices Every goddamn object Q: Who's responsible

    for this mess Q: Where can I see this code in more detail? A: github.com/kkuchta/druby Q: Should I use this in production? A: De f initely! FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  137. @[email protected] / @kkuchta Microservices Every goddamn object Q: Who's responsible

    for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/druby Q: Should I use this in production? A: De f initely! FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  138. @[email protected] / @kkuchta Microservices Every goddamn object Q: Who's responsible

    for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/druby Q: Should I use this in production? A: De f initely! Q: I have a real question FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  139. @[email protected] / @kkuchta Microservices Every goddamn object Q: Who's responsible

    for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/druby Q: Should I use this in production? A: De f initely! Q: I have a real question A: Right here! FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  140. @[email protected] / @kkuchta Microservices Every goddamn object Q: Who's responsible

    for this mess A: Kevin Kuchta, @kkuchta, kevinkuchta.com Q: Where can I see this code in more detail? A: github.com/kkuchta/druby Q: Should I use this in production? A: De f initely! Q: I have a real question A: Right here! Q: Who's paying you to do this nonsense FAQ Q: What's a good use for druby for? A: Smaller, internal projects class SomeClass def foo puts [1,2,3].map { puts "hi" } end end obj = SomeClass.new obj.foo Remote Remote Remote Remote
  141. @[email protected] / @kkuchta Credits - Poorly Drawn Lines comic -

    https://poorlydrawnlines.com/comic/an-idea/ - https://creativecommons.org/licenses/by-nc/3.0/