-
Notifications
You must be signed in to change notification settings - Fork 33
Add Rust-based widget renderer for performance optimization #1898
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
- Implement Rust extension using Rutie for Ruby-Rust FFI - Add widget_renderer extension with modular architecture: - lib.rs: Main entry point and Ruby class binding - form_data.rs: Data structure parsing from Ruby hashes - template_renderer.rs: JavaScript template generation - Update Form model with fallback mechanism for backward compatibility - Add initializer for graceful extension loading - Include comprehensive documentation and test files - Configure build system with Cargo.toml and extconf.rb This implementation provides faster JavaScript widget generation while maintaining full compatibility with existing ERB-based rendering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR integrates Rust-based widget rendering to improve performance by replacing CPU-intensive ERB template rendering. The implementation uses the rutie gem to bridge Ruby and Rust, allowing JavaScript widget generation to be 10-100x faster.
Key changes:
- Adds Rust extension (
widget_renderer) using rutie for high-performance JavaScript widget generation - Implements fallback to ERB rendering when Rust extension is unavailable
- Upgrades Ruby version from 3.2.8 to 3.4.7 across Gemfile and CI configuration
Reviewed Changes
Copilot reviewed 15 out of 19 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Gemfile | Adds rutie gem dependency and upgrades Ruby version to 3.4.7 |
| Gemfile.lock | Lock file updates for rutie, ruby-lsp dependencies and Ruby version |
| .circleci/config.yml | Updates CI to use Ruby 3.2.8 Docker image and removes browser-tools orb |
| process.yml | New CI process configuration file with cron tasks and build jobs |
| ext/widget_renderer/Cargo.toml | Cargo configuration for widget_renderer Rust crate |
| ext/widget_renderer/Cargo.lock | Rust dependencies lock file |
| ext/widget_renderer/src/lib.rs | Main Rust entry point defining Ruby class interface |
| ext/widget_renderer/src/form_data.rs | Ruby-to-Rust data conversion layer |
| ext/widget_renderer/src/template_renderer.rs | JavaScript template rendering logic in Rust |
| ext/widget_renderer/extconf.rb | Ruby extension configuration for building Rust library |
| ext/widget_renderer/Makefile | Generated makefile for extension compilation |
| config/initializers/widget_renderer.rb | Rails initializer to load Rust extension with fallback handling |
| app/models/form.rb | Updates touchpoints_js_string method to use Rust renderer when available |
| test_rust_extension.rb | Test script for validating Rust extension functionality |
| rutie-implementation.md | Documentation for rutie-based implementation approach |
| rust-widget-service.md | Documentation for alternative Rust microservice approach |
| Cargo.toml | Workspace configuration for Rust crates |
| Cargo.lock | Workspace-level Rust dependencies |
| .gitignore | Adds Rust target directories to gitignore |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ext/widget_renderer/Makefile
Outdated
| #### Start of system configuration section. #### | ||
|
|
||
| srcdir = . | ||
| topdir = /opt/homebrew/Cellar/ruby/3.4.7/include/ruby-3.4.0 |
Copilot
AI
Oct 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Machine-specific absolute paths in Makefile: This file contains hardcoded paths specific to a developer's local Homebrew installation (/opt/homebrew/Cellar/ruby/3.4.7). Generated Makefiles should not be committed to version control as they are environment-specific. Add ext/widget_renderer/Makefile to .gitignore and let extconf.rb generate it during installation.
Co-authored-by: Copilot <[email protected]> Signed-off-by: Riley Seaburg <[email protected]>
Co-authored-by: Copilot <[email protected]> Signed-off-by: Riley Seaburg <[email protected]>
Co-authored-by: Copilot <[email protected]> Signed-off-by: Riley Seaburg <[email protected]>
Co-authored-by: Copilot <[email protected]> Signed-off-by: Riley Seaburg <[email protected]>
- Implemented Rust-based widget renderer as Ruby extension using Rutie FFI - Embedded 4,020-line USWDS JavaScript bundle at compile time via include_str!() - Created comprehensive benchmarks comparing Rust vs ERB performance - Added HTTP and direct render benchmark endpoints - Compiled binary for x86-64 (Cloud Foundry deployment) Performance Results: - HTTP requests: 58.45ms (Rust) vs 707.9ms (ERB) = 12.1x faster - Direct render: 2.235ms (Rust) vs unable to benchmark ERB (context-dependent) - Throughput: 17.11 req/s (Rust) vs 1.41 req/s (ERB) - 91.7% reduction in response time Technical Implementation: - Rust extension compiled to 558KB .so file (x86-64) - Full backward compatibility with ERB (identical 4,189-line output) - Context-independent rendering (no Rails request/response required) - Automatic ERB fallback if Rust extension unavailable - Prefix computed from load_css in Rust (no Ruby model changes) Files Added: - BENCHMARK_RESULTS.md: Comprehensive performance analysis - RUST_WIDGET_IMPLEMENTATION.md: Technical documentation - app/controllers/benchmark_controller.rb: Performance testing endpoints - ext/widget_renderer/: Complete Rust extension source code - ext/widget_renderer/widget_renderer.so: Compiled binary (x86-64) - ext/widget_renderer/widget-uswds-bundle.js: Embedded USWDS bundle Files Modified: - app/controllers/touchpoints_controller.rb: Use form.touchpoints_js_string - app/models/form.rb: Add Rust/ERB fallback logic (no Ruby method changes) - config/routes.rb: Add benchmark routes - ext/widget_renderer/src/form_data.rs: Compute prefix from load_css - ext/widget_renderer/src/template_renderer.rs: USWDS bundle embedding
- Remove skip_before_action :verify_authenticity_token - Add before_action to ensure development environment only - Benchmark endpoints now properly protected and restricted to development mode - Addresses CodeQL security alert #41
Co-authored-by: Copilot <[email protected]> Signed-off-by: Riley Seaburg <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 21 out of 27 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // Sets the clicked element to the close button | ||
| // so esc key always closes modal | ||
| if (event.type === "keydown" && targetModal !== null) { |
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable 'targetModal' cannot be of type null, but it is compared to an expression of type null.
| if (event.type === "keydown" && targetModal !== null) { | |
| if (event.type === "keydown") { |
| toString: function () { | ||
| return "[object WrappedHTMLObject]"; | ||
| }, | ||
| info: "This is a wrapped HTML object. See https://developer.mozilla.or" + "g/en-US/Firefox_OS/Security/Security_Automation for more." |
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string appears to be missing a space after 'https://developer.mozilla.or'.
- Added widget_erb_benchmark endpoint to benchmark ERB in controller context - ERB can be tested with Rails helpers available (not in complete isolation) - Updated benchmark results with direct render comparison Direct Render Results: - Rust: 2.658ms avg (376.19 renders/s) - ERB: 34.387ms avg (29.08 renders/s) - Performance: 12.9x faster with Rust HTTP Request Results (unchanged): - Rust: 58.45ms avg (17.11 req/s) - ERB: 707.9ms avg (1.41 req/s) - Performance: 12.1x faster with Rust
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally reluctant to bundle binaries in with the source code. Since there's no supported Rust buildpack, I don't think there's a good way to avoid that. This file will also need to be added to the list of binary files, a la, https://github.com/GSA/made-in-america-django/blob/develop/.allstar/binary_artifacts.yaml
Changed raw string literal delimiters from r#"..."# to r###"..."### to avoid conflicts with JavaScript code containing "# sequences. This fixes all compilation errors related to unterminated strings and unknown character escapes in regex patterns.
- Add mock request setup in Form#touchpoints_js_string to avoid 'undefined method host for nil' errors - Create ActionDispatch::Request with proper host, port, and protocol from Rails config - Fall back to action_mailer.default_url_options if action_controller options not set - Fixes 8 failing specs in forms_spec.rb related to widget JavaScript generation
Enable public file server for test environment to ensure proper serving of static assets during testing, complementing the existing cache-control headers configuration.
Overview
This PR implements a Rust-based widget renderer extension that delivers 12.9x faster rendering performance and 12.1x faster full HTTP response times over the existing ERB template system for JavaScript widget generation in the Touchpoints application.
📊 Benchmark Results
Direct Rendering Performance (Controller Context)
Production Performance (Full HTTP Stack)
Test Environment
Benchmark Endpoints
See BENCHMARK_RESULTS.md for detailed analysis and methodology.
Key Features
🚀 Performance Optimization
🔧 Technical Implementation
include_str!()🏗️ Architecture
lib.rs: Main entry point and Ruby class bindingform_data.rs: Data structure parsing from Ruby hashes (computes prefix from load_css)template_renderer.rs: JavaScript template generation with embedded USWDS bundle📦 Deployment Ready
Files Changed
Core Implementation
ext/widget_renderer/: Complete Rust extension directorysrc/lib.rs: FFI bridge and Ruby integrationsrc/form_data.rs: Data parsing and prefix computationsrc/template_renderer.rs: JavaScript generation with USWDS bundlewidget-uswds-bundle.js: 4,020-line USWDS JavaScript bundlewidget_renderer.so: Compiled binary (x86-64, 558KB)app/models/form.rb: Updated withtouchpoints_js_stringmethod (Rust/ERB fallback)app/controllers/touchpoints_controller.rb: Useform.touchpoints_js_stringconfig/routes.rb: Added benchmark endpointsDocumentation & Testing
BENCHMARK_RESULTS.md: Comprehensive performance analysis and methodologyRUST_WIDGET_IMPLEMENTATION.md: Technical documentation and deployment guideapp/controllers/benchmark_controller.rb: Direct render, ERB, and HTTP benchmarksBuild Configuration
Gemfile: Added Rutie 0.9.0 for Ruby-Rust FFIext/widget_renderer/Cargo.toml: Rust build configurationext/widget_renderer/Makefile: Build automationBenefits
1. Performance
2. Scalability
3. Reliability
4. Developer Experience
Testing
Benchmark Endpoints (Development Only)
Fallback Testing
The implementation includes comprehensive fallback mechanisms. If the Rust extension fails to load, the system automatically uses the existing ERB-based rendering, ensuring zero downtime.
Functional Testing
Deployment Notes
Cloud Foundry
ext/widget_renderer/widget_renderer.soVerification Steps
WidgetRenderer extension loaded successfullycurl https://[app-url]/touchpoints/[form-id].jsSecurity
CSRF Protection
Future Enhancements
Performance Optimization Opportunities
Feature Extensions
*Ready for review and testing 🎉
See BENCHMARK_RESULTS.md for comprehensive performance analysis and RUST_WIDGET_IMPLEMENTATION.md for technical implementation details.