Ruby

Nginx + Mruby. Features and Use Cases

Balkan Ruby 2019

00:00:19.580 Thank you.
00:00:22.550 Hi everyone, my name is Sergey Alekseenko. You can find me on GitHub, and feel free to contact me on Telegram or by email.
00:00:27.420 Actually, I'm Russian; I'm from Siberia. It was around -38 degrees this winter where I'm from, Tomsk. I've included some photographs of Tomsk.
00:00:38.879 I've been working as a back-end developer at Service.com for about a year. This company is based in Cyprus, which is a really sunny island, and we focus on server hosting automation using Ruby.
00:01:01.579 Today, I'm going to talk about MRuby. The first question is: what is MRuby? Has anyone heard of MRuby? Please raise your hand.
00:01:23.939 Great! So, MRuby is a lightweight implementation of the Ruby language that complies with a part of the ISO standard. The main feature is that you can embed MRuby code into your application. The current version is 2.0, but I first encountered MRuby when version 1.4 was available.
00:01:39.540 Now, how can we build MRuby? The first step is to clone the MRuby repository from GitHub. When you do this, you will see an interesting configuration file called build_config.rb. This file provides a lot of configuration options; for example, you need to select a compiler such as GCC.
00:02:49.460 After making your configurations, you can compile MRuby using the mini awake script. Once compiled, your MRuby build will be located in the 'built/host' directory. Inside that directory, you'll find a 'bin' directory containing a few binaries. The first is 'mruby', which is an interpreter program, and the second is 'mIRB', an interactive shell similar to IRB and MRI.
00:03:10.200 Additionally, MRuby provides external libraries known as gems or MRuby gems. There is an MRuby gems package manager that you can use. If you want to add gems to your MRuby build, you need to reference them in your configuration file.
00:03:32.490 There are gem repositories available, and if you find your gem in one of these repositories, you can simply use the 'gem' option. If your desired gem is hosted on GitHub, you can use its GitHub repository for that. You can also extract your gems to a specific file named 'gem_box' and include your gem box directly in your configuration file.
00:04:21.400 Next, let's attempt to write some Ruby code. This code uses what looks like pure Ruby syntax, and we can execute it using the MRuby interpreter binaries, which will print 'Hi everyone, it’s okay'.
00:04:34.550 Furthermore, we can try compiling the same script using 'mrb -c' and specify our output file with an '.mrb' extension, and we should see the same result. An interesting example is executing our script directly from a C program.
00:05:11.540 Here’s a small example of a C program. At the beginning of the file, you can include some necessary headers, define a pointer to the 'MRuby state' structure, handle errors accordingly, and, if all is well, open your script and call the 'mrb_load_file' function to execute your Ruby code.
00:05:21.650 After that, you can compile your C program using GCC and link it with MRuby libraries. The output file could be named 'mruby_c', and when executed, it should produce the same result.
00:05:43.960 Now, let’s discuss updating our code. I improved my hello method by adding an iteration count, but I didn't recompile the C application; I just updated the MRuby code. When we run our binaries again, we see that the output reflects these changes.
00:06:19.310 Comparing Ruby with MRuby, we notice some limitations. The first critical limitation is method visibility. If we declare a method as private, we can still call it without any issue.
00:06:49.350 Another limitation pertains to the 'require' functionality. For example, if we have two classes in separate files, and we attempt to require Class A from Class B, we may encounter issues with method definitions and requirements which might not work as expected in MRuby.
00:07:59.420 Lexicographical ordering is another problem. As shown in the pictures with files prefixed by numbers, the order is not guaranteed. However, there is an open pull request from Vladimir Dementiev to add magic comments that may enhance the 'require' functionality.
00:08:41.300 MRuby core does not include support for regular expressions. If you need regex functionality, you could use gems such as 'mruby-rex' or others based on the Enigma library. There are also limitations regarding thread and process support.
00:09:05.650 Many additional limitations can be found in the official MRuby documentation. Now, let's look at some examples and projects that utilize MRuby.
00:09:19.480 The first example is MRuby-CLI, which provides a platform for building native command-line applications across various operating systems such as Linux, Windows, and macOS. It includes necessary tools for creating standalone binaries from any machine.
00:10:43.590 There's also an interesting talk about MRuby at RubyConf 2016, which you can find via a YouTube link or search online. The next example is 'Meter My', a configuration management system inspired by Chef. It allows you to write scripts and configurations without using Ruby because it utilizes MRuby.
00:11:21.870 Another project is 'Trust Earth', a web performance HTTP/2 web server built with nghttp2 and MRuby. This solution facilitates fast deployment of HTTP/2 web servers.
00:11:43.870 If you are a Go developer, you can integrate MRuby into your applications using bindings provided by the Go language. This lets you execute MRuby code from your Go application or run Go code from within Ruby.
00:12:05.000 A notable example is 'AnyCable Go', which many in the community are aware of. Shopify has also provided an example called 'Ruby Engine.' It is a sandbox scripting engine that wraps MRuby into an external gem that can be easily integrated into your Rails application.
00:12:52.000 Let’s return to coding. Here, we have a small class with a simple method. You should prefix instance variable names with '@' to ensure they are interpreted correctly by MRuby.
00:13:21.880 To execute MRuby code from Ruby, you need to require the 'mruby_engine', define some queries, and create an MRuby engine instance, providing your MRuby script to the 'sandbox_eval' method. This way, your code will be executed, and you can retrieve results from instance variables.
00:14:29.240 MRuby has a fascinating tutorial about WebAssembly and a project called 'mruby-wasm'. The MRuby community is vibrant, particularly in Japan, with many resources for learning and using MRuby for embedded systems and microcontrollers.
00:15:07.370 An exciting implementation of MRuby is 'mruby-c', designed to fit into very small environments, with a size of less than 40 kilobytes, which is particularly suitable for microcontrollers.
00:15:41.850 Regarding my personal experience with MRuby, I encountered it while working at Teach Boys Company as CTO. We had numerous customers with custom domains, and we needed to automate the registration of SSL certificates and other configurations.
00:16:31.760 Initially, we attempted multiple engines for each customer to handle different domains, but it proved difficult to manage. Instead, we looked into embedding MRuby into our Nginx server to create a more integrated solution.
00:17:16.590 The MRuby extension for Nginx allows us to create directives to utilize Ruby scripts within various HTTP request phases, significantly enhancing our configuration's flexibility.
00:18:06.320 By using directives like 'mruby_content_handler', we can embed Ruby code directly in our Nginx configuration files, allowing for dynamic request handling and manipulation of scripts.
00:19:17.340 Moreover, we can set up caching for our scripts to ensure they are only executed once per request unless it needs to change dynamically. This is very useful for optimizing performance.
00:20:23.130 We can implement SSL handling using MRuby, allowing us to dynamically adjust certificates based on requests, which smartly integrates into our existing configurations.
00:21:21.810 In production, we've found that using user data instances can be problematic across multiple Nginx workers, requiring careful management to avoid conflicts or data inconsistencies.
00:22:57.760 We've also learned to create fault-tolerant systems by having fallbacks to the file system for SSL certificates when Redis faces issues. This way, we ensure that downtime is minimized.
00:24:49.120 Thank you for your attention.