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

Everything a Microservice: The Worst Possible Intro to Druby

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 x = "this is a micro service"

  2. @[email protected] / @kkuchta x = "this is a micro service"

  3. @[email protected] / @kkuchta x = "this is a micro service"

  4. @[email protected] / @kkuchta Microservices What do we know

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

    services, but smaller
  6. @[email protected] / @kkuchta Microservices What do we know A. Regular

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

    services, but smaller B. Better than services C. Smaller = better
  8. @[email protected] / @kkuchta Microservices What is the optimal size?

  9. @[email protected] / @kkuchta Microservices What is the optimal size? 1.

    Concept
  10. @[email protected] / @kkuchta Microservices What is the optimal size? 1.

    Concept 2. Model
  11. @[email protected] / @kkuchta Microservices What is the optimal size? 1.

    Concept 2. Model 3. Concern
  12. @[email protected] / @kkuchta Microservices What is the optimal size?

  13. @[email protected] / @kkuchta Microservices What is the optimal size?

  14. @[email protected] / @kkuchta x = SomeObject.new

  15. @[email protected] / @kkuchta Microservices Every goddamn object local.rb remote.rb

  16. @[email protected] / @kkuchta Microservices Every goddamn object class SomeClass def

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

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

    foo puts "hi" end end obj = SomeClass.new obj.foo local.rb remote.rb
  19. @[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
  20. @[email protected] / @kkuchta Because Microservices

  21. @[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
  22. @[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
  23. @[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
  24. @[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
  25. @[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
  26. @[email protected] / @kkuchta Everything a Microservice Kevin Kuchta He/him Daybreak

    Health The worst possible intro to dRuby
  27. @[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
  28. @[email protected] / @kkuchta Remote Objects local.rb remote.rb foo = (something)

    output = foo.bar
  29. @[email protected] / @kkuchta Remote Objects local.rb remote.rb foo = (something)

    output = foo.bar # bar runs over here
  30. @[email protected] / @kkuchta dRuby

  31. @[email protected] / @kkuchta dRuby $ gem install drb

  32. @[email protected] / @kkuchta dRuby the good parts

  33. @[email protected] / @kkuchta dRuby the good parts local.rb

  34. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb

  35. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb'
  36. @[email protected] / @kkuchta dRuby the good parts local.rb remote.rb require

    'drb/drb' class RemoteServer def foo; puts "foo ran here"; end end
  37. @[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(
  38. @[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',
  39. @[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 )
  40. @[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
  41. @[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
  42. @[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
  43. @[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
  44. @[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
  45. @[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
  46. @[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
  47. @[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
  48. @[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
  49. @[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
  50. @[email protected] / @kkuchta Remote Objects automagic local.rb remote.rb class SomeClass

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

    SomeClass def foo; end end object = remote_new(SomeClass) object.foo
  52. @[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)
  53. @[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)
  54. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteObject

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

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

    def foo SomethingWeird.new end end result = remote.foo
  57. @[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
  58. @[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()
  59. @[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
  60. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class SomethingWeird

    include DRb::DRbUndumped end
  61. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end
  62. @[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
  63. @[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' )
  64. @[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)
  65. @[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
  66. @[email protected] / @kkuchta Remote Objects proxying local.rb remote.rb class RemoteNewer

    def make_new(klass) klass.new() .extend(DRb::DRbUndumped) end end
  67. @[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
  68. @[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
  69. @[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
  70. @[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')
  71. @[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")
  72. @[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
  73. @[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
  74. @[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
  75. @[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
  76. @[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
  77. @[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
  78. @[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
  79. @[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
  80. @[email protected] / @kkuchta Remote Objects Remote Object Everywhere local.rb remote.rb

  81. @[email protected] / @kkuchta Remote Objects Remote Object Everywhere local.rb remote.rb

    remote = DRbObject .new_with_uri('druby://localhost:5555')
  82. @[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")
  83. @[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)
  84. @[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)
  85. @[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")
  86. @[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
  87. @[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
  88. @[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
  89. @[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
  90. @[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
  91. @[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
  92. @[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
  93. @[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
  94. @[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
  95. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb

  96. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3])
  97. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) sum = arr.sum
  98. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) sum = arr.sum arr.include?(2)
  99. @[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")
  100. @[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 }
  101. @[email protected].social / @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 }
  102. @[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 }
  103. @[email protected] / @kkuchta Microservices friggin' procs

  104. @[email protected] / @kkuchta Microservices friggin' procs some_remote_object.foo(arg1)

  105. @[email protected] / @kkuchta Microservices friggin' procs some_remote_object.foo(arg1) # Under the

    hood: Marshal.dump(arg1)
  106. @[email protected] / @kkuchta Microservices friggin' procs some_remote_object.foo(arg1) # Under the

    hood: Marshal.dump(arg1) some_remote_object.foo { |x| x + 1 }
  107. @[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 })
  108. @[email protected] / @kkuchta Microservices friggin' procs > dumped = Marshal.dump({a:

    1})
  109. @[email protected] / @kkuchta Microservices friggin' procs > dumped = Marshal.dump({a:

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

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

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

  113. @[email protected] / @kkuchta Microservices friggin' procs Marshal.dump(proc { |x| x

    + 1 })
  114. @[email protected] / @kkuchta Microservices friggin' procs Marshal.dump(proc { |x| x

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

    { |x| x + y }) # TypeError: no _dump_data is # defined for class Proc
  116. @[email protected] / @kkuchta Microservices friggin' procs class Proc end

  117. @[email protected] / @kkuchta def _dump(depth) Microservices friggin' procs class Proc

    end
  118. @[email protected] / @kkuchta def _dump(depth) serialize_block(&self) end Microservices friggin' procs

    class Proc end
  119. @[email protected] / @kkuchta def _dump(depth) serialize_block(&self) end Microservices friggin' procs

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

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

    friggin' procs class Proc end "{ |x| x + 1 }"
  122. @[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 }"
  123. @[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 }"
  124. @kkuc[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block
  125. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block some_proc = proc do |x| x + 1 end
  126. @[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
  127. @[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]
  128. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block
  129. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block require 'method_source'
  130. @[email protected] / @kkuchta Microservices friggin' procs 1. Find the source

    of a block require 'method_source' some_proc = proc do |x| x + 1 end
  131. @[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"
  132. @[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
  133. @[email protected] / @kkuchta Microservices friggin' procs 2. Parse out the

    actual block with the SyntaxTree gem "some_proc = proc { |x| x + 1 }"
  134. @[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 }"
  135. @[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 }"
  136. @[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 }"
  137. @[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 }"
  138. @[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 }"
  139. @[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 }"
  140. @[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 }"
  141. @[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 }"
  142. @[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
  143. @[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
  144. @[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
  145. @[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
  146. @[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
  147. @[email protected] / @kkuchta Microservices friggin' procs local.rb remote.rb arr =

    Array.new([1,2,3]) arr.each { |i| puts i }
  148. @[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 }
  149. @[email protected] / @kkuchta Microservices literally the worst arr = [1,2,3]

    str = "foo" hash = {a: 1, b: 2}
  150. @[email protected] / @kkuchta Microservices literally the worst class Array def

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

    self.new puts "new called" end end Array.new # "new called"
  152. @[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
  153. @[email protected] / @kkuchta Microservices literally the worst x = [1,2,3]

    x = Array.new([1,2,3])
  154. @[email protected] / @kkuchta Microservices literally the worst DATA

  155. @[email protected] / @kkuchta Microservices literally the worst DATA

  156. @[email protected] / @kkuchta Microservices literally the worst puts "hi" puts

    DATA.read()
  157. @[email protected] / @kkuchta Microservices literally the worst puts "hi" puts

    DATA.read() __END__
  158. @[email protected] / @kkuchta Microservices literally the worst puts "hi" puts

    DATA.read() __END__ hello there, world, how are you?
  159. @[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?"
  160. @[email protected] / @kkuchta Microservices literally the worst puts "hi" puts

    DATA.read() __END__ arr = [1,2,3]
  161. @[email protected] / @kkuchta Microservices literally the worst puts "hi" eval(DATA.read())

    __END__ arr = [1,2,3]
  162. @[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])
  163. @[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"
  164. @[email protected] / @kkuchta Peak Architecture less distributed

  165. @[email protected] / @kkuchta Peak Architecture more distributes

  166. @[email protected] / @kkuchta Peak Architecture more distributes

  167. @[email protected] / @kkuchta Peak Architecture more distributed def handler(event:, context:)

    x = event['x'] return x * 2 end
  168. @[email protected] / @kkuchta Peak Architecture more distributed def handler(event:, context:)

    # ... end
  169. @[email protected] / @kkuchta Peak Architecture more distributed def lambda_handler(event:, context:)

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

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

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

    Object # ... def self.remote_new(*args, **kwargs, &block) end end
  173. @[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()
  174. @[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
  175. @[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"
  176. @[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)
  177. @[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)
  178. @[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)
  179. @[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
  180. @[email protected] / @kkuchta Peak Architecture more distributes

  181. @[email protected] / @kkuchta Peak Architecture more distributes

  182. @[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
  183. @[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"
  184. @[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
  185. @[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
  186. @[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
  187. @[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
  188. @[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
  189. @[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
  190. @[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
  191. @[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
  192. @[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
  193. @[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
  194. @[email protected] / @kkuchta # local.rb: arr = [1,2,3] str =

    "whatever" puts arr.map { |x| x * 2} str.each_char { |c| puts c }
  195. @[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 }
  196. @[email protected] / @kkuchta Microservices Every goddamn object

  197. @[email protected] / @kkuchta Microservices Every goddamn object

  198. @[email protected] / @kkuchta Microservices Every goddamn object

  199. @[email protected] / @kkuchta slower, more expensive, complex

  200. @[email protected] / @kkuchta Microservices! slower, more expensive, complex

  201. @[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
  202. @[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
  203. @[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
  204. @[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
  205. @[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
  206. @[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
  207. @[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
  208. @[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
  209. @[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
  210. @[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
  211. @[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
  212. @[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
  213. @[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
  214. @[email protected] / @kkuchta DaybreakHealth.com [email protected] https://daybreakhealth.applytojob.com/apply/

  215. @[email protected] / @kkuchta Thank You DaybreakHealth.com [email protected] https://daybreakhealth.applytojob.com/apply/

  216. @[email protected] / @kkuchta Credits - Poorly Drawn Lines comic -

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