Sales Software Modernization Case Study: Rails 7 Upgrade
Business Requirement
Our client, a US-based organization, provides sales software for HVAC dealers and distributors. Their applications used Ruby v2.x with Rails v4.x for backend processing and PostgreSQL for data storage. Delayed jobs handled background tasks, and HTML was used for templating. These software versions, however, had increasing security vulnerabilities, performance issues, and lacked compatibility with modern tools and practices.
Objectives
The main goal was to upgrade the applications from Ruby 2.x to 3.2 and Rails from 4.x to 7.2, along with key infrastructure enhancements:
- Moving the RDS to a private subnet to enhance security.
- Consolidating applications into ECS containers for better scalability.
- Setting up a CI/CD pipeline to streamline development and deployment.
- Migrating sensitive information management to AWS Secret Manager for improved security.
Our Approach
We began by developing a comprehensive plan that detailed each step of the upgrade process, including the necessary codebase refactoring and infrastructure enhancements. This plan outlined our deployment strategies to ensure minimal downtime and disruption. During the development phase, we performed incremental upgrades to Rails and Ruby, refactored the codebase for compatibility, and addressed performance improvements. We implemented a robust CI/CD pipeline using tools like Jenkins and Terraform to automate and manage the infrastructure consistently.
Extensive testing was conducted throughout the project, including internal testing and user acceptance testing (UAT), to identify and resolve issues before the final deployment. We scheduled a maintenance window to minimize disruption and closely monitored the deployment to ensure a smooth transition. Regular communication with the client kept them informed and involved, ensuring that any concerns were promptly addressed, leading to a successful upgrade.
The Solution
Application Modernization
- Incremental Upgrade of Rails: We upgraded Rails incrementally from version 4 to 7.2. This step-by-step approach allowed us to resolve compatibility issues progressively and ensured a stable transition at each stage.
- Incremental Upgrade of Ruby: Ruby was upgraded from version 2.x to 3.2. This included addressing syntax changes, updating gems, and removing deprecated features to ensure smooth operation with the latest version.
- Turbo Frames and Turbo Streams Implementation: Implemented Turbo Frames and Turbo Streams to enhance client-server communication, resulting in faster and more efficient data handling.
- Migration from Paperclip to Active Storage: The application’s file storage was migrated from Paperclip to Active Storage, providing better integration with modern Rails applications and support for cloud storage services.
- Adoption of Import Maps: Import Maps were adopted for JavaScript dependency management, simplifying asset management and improving loading times.
- Switch from Unicorn to Puma: Switched the web server from Unicorn to Puma to leverage better threading capabilities and improve performance under concurrent request loads.
- Migration from Delayed Job to Active Jobs with Sidekiq: Migrated background job processing from Delayed Job to Active Jobs with Sidekiq, enhancing job processing efficiency and reliability.
Infrastructure Enhancements
- Moved the RDS database to a private subnet to enhance security and prevent direct exposure to the internet. Also enabled read replicas for better performance.
- Consolidated all applications into ECS containers with auto-scaling capabilities, ensuring better resource utilization and scalability.
- Configured real-time monitoring and alerts for CPU, memory, and disk utilization. Integrated these alerts with New Relic and Slack for immediate notifications and quicker response times to potential issues.
Security Enhancements
- Migrated sensitive information, such as API keys and database credentials, to AWS Secret Manager. This provided a secure and scalable solution for managing secrets and improved overall security posture.
Local Development and Deployment
- Standardized local development using Docker: Implemented Docker for local development to ensure consistency between development and production environments, reducing the "it works on my machine" problem.
- Deployed services on Fargate: Deployed services on AWS Fargate, which simplified the management of containerized applications and allowed for serverless operations.
- Codebase Clean-up: Updated code syntax, upgraded gems, and removed unused dependencies to streamline the codebase, making it more maintainable and efficient.
Data Preparation and Deployment
- Scheduled Maintenance Window: Scheduled a maintenance window to minimize disruption during the upgrade process. This was communicated to all stakeholders in advance to prepare for the temporary downtime.
- Extensive Beta Testing: Conducted thorough beta testing to identify and resolve potential issues before the final production move. This included both internal testing and user acceptance testing (UAT).
- Monitored Deployment: Closely monitored the final deployment to ensure a smooth transition and promptly addressed any issues that arose.
Benefits to Customer
Enhanced Security
The application running on Rails 4 had 34 vulnerabilities within the Docker image. After upgrading to Rails 7, the security landscape improved significantly, with only 2 low-level vulnerabilities remaining. This reduction in vulnerabilities has enhanced the application's security.
Performance
With the server configuration under Rails 4, CPU utilization frequently ranged between 70-90%, and memory usage was consistently high. After upgrading to Rails 7, with the same server configuration, CPU utilization dropped to 20-30%, and memory usage stabilized between 30-40%, even during peak business hours. This reduction in resource usage improved the application's performance and responsiveness.
Cost Efficiency
The reduction in CPU and memory utilization directly translated into lower operational costs. With improved performance, the same tasks require fewer resources, allowing for the potential scaling down of server capacities and thereby reducing cloud infrastructure costs.
Initially, our cloud infrastructure relied on servers with 16 vCPUs and 32 GB RAM. Following our migration from Rails 4 to 7, Ruby 2.x to 3.2, and a few more performance optimizations, we successfully downsized to servers with 8 vCPUs and 16 GB RAM. This strategic shift not only maintained but improved our application's performance while reducing our cloud computing costs by approximately 35%.
Cleaner Codebase
Refactoring the codebase, updating syntax, and removing unused dependencies made the application more maintainable and easier to extend. This not only improved the readability of the code but also facilitated quicker onboarding of new developers and faster implementation of new features.
Simplified Deployment
Implementing a comprehensive CI/CD pipeline automated the build, test, and deployment processes. This reduced the manual effort involved in deployments, minimised human errors, and ensured consistent and reliable application releases. Docker and Terraform further streamlined the deployment process, making it more predictable and easier to manage.
Conclusion
The Rails 7 upgrade has significantly improved security, performance, and cost efficiency, resulting in more stable and reliable applications. Enhancements included addressing vulnerabilities, integrating AWS services, and optimizing performance, which reduced CPU and memory usage. The modernized codebase is easier to maintain and extend, and the new CI/CD pipeline streamlined deployments. Using Docker and Terraform ensured consistent, reproducible deployments. This project transformed the application into a secure, efficient, and future-ready solution, demonstrating our commitment to impactful solutions.
Your one-stop shop for expert RoR services.
Join 250+ companies achieving top-notch RoR development without increasing your workforce.