Page MenuHomePhabricator

Proposal: Improve performance of slow routes in Programs & Events Dashboard
Closed, ResolvedPublic

Assigned To
Authored By
Abishekdascs
Apr 14 2025, 4:00 PM
Referenced Files
F65930896: Uptime Graph.png
Aug 29 2025, 1:11 PM
F65910677: uptime progress.png
Aug 25 2025, 4:40 PM
F59062658: Backend optimization Flow.png
Apr 14 2025, 4:00 PM
F59062681: reactredux.png
Apr 14 2025, 4:00 PM

Description

Profile Information:

Name: Abishek Das
Nickname: Abishekcs
Github: Abishekcs
Email: abishekdascs@gmail.com
Location: India
Time Zone: India (UTC+5.30)

Meeting with mentors:

  • Reachable anytime through slack, email, Zulip.
  • UTC 11:30 AM to 8:30 PM (IST 5:00 PM – 2:00 AM)

Typical Working hours:

  • UTC 7:30 AM to 3:30 PM (IST 1:00 PM – 9:00 PM)

Synopsis:

[Programs & Events Dashboard] Improve performance of slow routes

The Wikimedia Programs & Events Dashboard is a web application designed for the global Wikimedia community. It handles a high volume of web traffic, which can lead to a poor user experience. Users often experience slow latency, meaning there is a noticeable delay between their actions and the browser rendering a usable response. In some cases, this performance lag can even contribute to site downtime.

The project aims to fix the worst performance issues and Improve the user exprience - to make the site "feel" faster and reduce site down by:

  • Improving backend efficiency: There are currently many indexes on the database tables that are not used efficiently, which leads to suboptimal performance.This includes issues like index cardinality problems, leadig to not using an index even if it will be useful for a search,like not using the entire composite index for searching, ordering or filtering.To identify these the slow query log feature on the Outreach Dashboard would be helpful, as it provides key information about the how the application queries data and investigate those slow SQL querys, which is essential for improving indexing.

    Also, many of the Dashboard's most serious problems revolve around N+1s queries, which appears across the application and in background jobs.

    Coming to caching based on the issues I've already worked on, I believe caching should be a last resort. If I can fix the SQL or optimize the view, I'll do that first. It's always better in the long run to fix the underlying problem rather than relying on caching.The reason is that well-optimized SQL queries can be often be just as fast as cache operations.Also,if we can get speed without adding something to the existing infrastrucure, we should do that instead.That said, if caching becomes necessary - especially for server-rendered views there's a good chance that "Russian Doll Caching" using fragment caching will be sufficient.Since, the Dashboard already uses Redis, with fragment caching redis will automatically evict old entries, so there will be little to no manual cache sweeping required.
  • Improving Ruby Code in the Backend: After optimizing the database and cache, the next layer to improve is the Ruby code running within Rails application — where excessive object allocations or inefficient logic can cause performance issues.Ruby's object allocations and memory usage can have a significant impact on performance, especially under heavy load.Factors like the time spent in Ruby and the number of objects created (i.e time spent on memory allocation) can become a serious bottleneck.

    My usual approach will be to profile the code locate slow sections, identify the root causes of the slowness, and rewrite the code to eliminate bottlenecks - then repeat the process until performance is improved.Since everything in Ruby is an object, programs often consume extra memory just to represent data.This high memory consumption is a major factor that can slow Ruby down.To optimize effectively, I will need to reduce the memory footprint. Doing so will reduce the time spent in garbage collection. The less memory the Dashboard's backend code uses, the less work Ruby's garbage collector has to do. Once I confirm that memory is being used optimally, I'll also analyze the algorithmic complexity fo the code as final step, ensuring that both memory and compute efficiency are aligned.
  • Improving frontend behavior: To improve the user exprience and make the site feel faster, it's important to focus on frontend (i.e Redux + React) as well because front end performance is really web applications performance from the users perspective.This includes enhancing the current state management system and optimizing how API are made through the frontend.One of the key improvements will be intergrating RTK query for few API routes, particularly those that fetch large amounts of data or are used by multiple components across the application. This will help prevent redundant data fetching, reduce load on the backend, and ensure that components can efficiently share cached data without triggering multiple unnecessary requests.Additionally, with the recent introductions of Infinite Query in RTK Query, it's now possible to load data in chunks or pages, which helps prevent the frontend from choking on large payloads, especially in components that deal with extensive datasets like article lists and article finder.

    On the React side, I plan to focus on reducing unnecessary re-renders, identifying memoization oppurtunities, and applying performance optimizations throughout the component tree.For instance, in the current implementation of the Details component, there's a slight input delay in all of the text area due to many state variables being held in the parent component rather than being localized in the child leading to re-render of all the child component when a text input changes which leads to noticable delay in input text area.Refactoring, this and other similar components will make interactions more responsive, prevent unnecessary re-renders and improve the overall performance of the UI.

This changes will greatly improve the performance of slow routes in Programs and Events Dashboard.

Mentors:

Sage Ross(@Ragesoss), formasit(@Formasit-chijoh)

Deliverables:

  • Improve Backend Efficiency through query optimization, indexing, and strategic caching.
  • Optimize Ruby Code in the Backend, focusing on Ruby performance optimization, memory usage, and object allocation.
  • Enhance Frontend Behavior by improving React performance and integrating Redux Toolkit with RTK Query.

Implementation Details:

These are the tools I will be using to detect performance issues and slow routes in the Programs and Events Dashboard codebase:

  • Rack-Mini-Profiler: Rack Mini Profiler is useful to profile database usage.It logs every SQL query that hit the database, showing how long each took and where it originated - including line number and parent calls.It's invalueable for figuring out where to apply eager loading properly.
  • Ruby Profilers: To investigate time spent in Ruby code, I will be using ruby profilers such as stack prof and ruby-prof.stackprof will be very easy to use since it's built in rack-mini-profiler.
  • Bullet: I will be using this gem to check when adding eager loading (N+1s queries) will be helpful and when we are using eager loading that isn't necessary and when we should use counter cache.
  • Prospite: Prosopite is a modern alternative to Bullet for detecting N+1 queries.Reasons, why I will also be using this because it's able to detect N+1 queries with zero false positives or false negatives a common issue with Bullet.
  • Query Count: Currently Rails 7.2 brings SQL queries count to template rendering logs.But since the dashboard is using Rails 7.0.7 it won't be possible.So, I will be using a Query Count gem that surfaces the number of queries that ran on a given page or endpoint.
  • New Relic: It is already used by the dashboard.This will help in examining request queue time and server response time that are slow and helpful in finding (N+1s queries).Also, the New Relic's Ruby VM tab can give a lot of informations about the memory behavior of Rails applications, which can in turn point to different performance issues and opputunities for improvement.
  • Eslint Plugin React Compiler: I will use this on the React side to identify unnecessary re-renders, spot memoization opportunities, and apply general performance optimizations. It helps enforce best practices and highlights areas in components where rendering efficiency can be improved.

Most of the major work for improving the slow routes in the Programs and Events Dashboard lies in the backend.For database optimization, I will be focusing on improving existing indexes and making sure they are fully utilized.Some key areas include adding indexes on columns that are frequently used in queries to speed up data retrieval, optimizing database queries to fetch only the required data, and reducing the number of database calls and finally making sure existing composite/mulitple index are fully utilized to their maximum capibility.

I will also work on optimizing ActiveRecord queries to make data access more efficient.For example, some the dashboard codebase often uses methods like count and exists?, which always execute a query and can lead to unncessary database roundtrips.

If needed, I will implement caching for frequently accessed data or costly operations.This will be done using fragment caching for specific parts of the views that are slow to render and where possible, I'll use Russian Doll caching to make it more efficient.I will also focus on optimizing background jobs and improving their performance.

Once the backend and database are optimized, I will move on to Ruby performance improvements, and finally shift focus to the frontend - specifically enhancing performance in React with Redux Toolkit (RTK) and RTK Query.

Due to this structure, I've divided the implmentation into three phases:

  • Phase 1: Improving backend efficiency
  • Phase 2: Improving backend efficiency + Ruby code optimization
  • Phase 3: Improving frontend behavior + backend and Ruby optimization

Details of each phase are explained in the Timeline Section.

Timeline

Phase 1: June 2 – July 1 (Improving backend efficiency)

  • Reduce the average reponse time of the following currently know enpoints which I discovered in my local development environment
    • CoursesController#articles
    • Surveys#results
    • Survey_assignment#index
    • Courses#manual_update
    • Ores_plot#campaign_plot
    • CampaignsController#ores_plot
    • CampaignsController#programs
    • CampaignsController#articles
    • CampaignController#users
    • RevisionFeedbackController#index
  • Improve performance for all the slow queries shown by the slow query log feature on the outreachdashboard server.
    • To reproduce this issues shown in productions locally I will be following this process:
      • Locate problems in production metrics, through APM that is New Relic in case of dashboard.
      • Replicate locally and profile the problem with Stackprof, rack-mini-profiler, Propsite, Query Count, etc to find what lines of code are causing the problem
      • Create a benchmark around the problem areas.
      • Iterate on a solution.
      • Let the solution code run in production.
      • Monitor the code
      • Then optimize it further if required and determine if cache is needed.
  • Many of the Dashboard's most serious problem revolves around N+1s.So, I will be fixing all of the obvious Major N+1s issues across the application and in background jobs too.
  • In addition to improving the /surveys/results performance, I will also fix all Bullet warnings related to the /surveys endpoints, including:
    • /surveys
    • /surveys/rapidfire/question_groups
    • /surveys/results
    • /surveys/results/
    • Most of these fixes involve straightforward changes such as adding or removing eager loading, based on Bullet's suggestions. However, Bullet also recommends using counter caches for some of these endpoints. Implementing this will require changes in the RapidFire fork used by the Dashboard. If adding counter caches results in a noticeable reduction in database queries, I plan to submit a fix to the RapidFire fork as well.
  • Fix all valid Bullet warnings across the Dashboard. Before implementing any changes suggested by Bullet, I will cross-check whether the warnings are accurate (i.e., not false positives or false negatives) and ensure they provide at least a minimal performance improvement to the Dashboard.
  • Fix all N+1 queries automatically detected by Prosopite. There were several cases where Bullet failed to detect N+1 queries for example, in CoursesController#articles — but Prosopite successfully identified them.These kind of performance detection by Prosopite will be addressed to improve database efficiency.
  • New Relic
    • Next, I will review the New Relic dashboard for controller actions and sort them by time consumed. This will help identify the top 10 most time-consuming controller actions, allowing me to focus my performance work where it will have the biggest impact on both user experience and backend performance.
    • And sort New Relic's transaction list by "longest response time", and look at the list.Improve the slowest-on-average transactions which have really bad N+1s which might be causing tens of thousands of allocations.

Phase 2: July 2 – July 31 (Backend Efficiency + Ruby Code Optimization)

  • Next I will try to improve performance through caching, keeping the following rule in mind before implementing it:
    • Is the data user specific or frequently changing dynamic data? If yes, then caching is probably not a good idea.
    • How often will the data change?
    • Can I make some other optimizatios instead?
      • First, optimize Dashboard queries.
      • Second, optimize Dashboard views.
      • Then, check if caching is still required.
    • If caching is a must to improve performance for a particular point in the dashbord then I will I'm going to apply these rules:
      • At what layer of the stack should the Cache be implemented?
      • Where does the most complexity of applying caching increase the most?
      • Under what conditions should the implemented cache be purged?
      • How long should the cache take to expire?
      • What kind of load/traffic does the dashboard have for that particular endpoint?
    • Also, make sure existing caching has a cache hit of 95% or more.
  • Optimize Active Record Queries
    • Improve performance of slow ActiveRecord query that takes 500ms or more.
    • Making sure count and exists? are only used where it is necessary since it always execute a query and can lead to unncessary database roundtrips.
    • Making sure not using .all everywhere since in development it's doesnt seem to harmful.But in productions it might return 100,000 of rows which might also lead ot ruby memory issue.
    • Avoid loading unnecessary columns with .select instead of using .all.Making sure selecting only those columns that are required.
  • Send only required data through JSON to React
    • Some of the JSON APIs in the Dashboard send data that is not used by React at all.For example CourseController#articles returns a large payload when accessed through the "Articles Edited" tab, but much of the JSON data is never actually used
    • I will work on redesigning some of these API endpoints to send only the data that is needed, reducing payload size and improving performance.
  • I will also specifically focus on the existing indexes in the database tables and check whether they are being fully utilized in the queries they support.If required, I will introduce new indexes to improve query peformance.To evaluate and optimize index usage, I will use the following MySQL query analysis features:
    • ANALYZE
    • ANALYZE FORMAT=JSON
    • EXPLAIN
    • EXPLAIN EXTENDED
  • Improve background jobs that operate on large datasets. I have yet to dive deeply into the codebase for this part, but I’m confident there will be opportunities for improvement. The Dashboard’s background jobs often deal with large result sets in ActiveRecord, which can significantly increase Ruby’s memory usage and slow down processing.
  • Ruby Code Optimization
    • Optimize high memory consumption in Ruby code throughout the Dashboard to reduce garbage collection time and overall memory usage.
    • To achieve this, I will focus on preventing unnecessary object allocations and memory leaks. Based on my research from various Ruby/Rails resources, most Rails applications create between 25,000 and 75,000 objects per transaction. While I’m not entirely sure how accurate these numbers are for this codebase, it's clear that excessive object allocation can negatively impact performance. If possible, I will try to speed up the application by either reducing the number of objects — doing the same work with fewer allocations — or by finding a completely different, more efficient approach where needed.
    • Write more efficient iterators that consume less time and memory, such as using .map as demonstrated in PR #6279.
    • When necessary, replace explicit iterators in views with render :collection, which is more memory- and time-efficient.

Phase 3: August 1 – August 29 (Improving frontend behavior + backend and Ruby optimization)

  • Continue with more backend and Ruby optimization.
  • Set up RTK and RTK Query. I already have a PR open for this (#6204). One of the current challenges is that using RTK Query adds some complexity, especially due to the existing folder structure. I will work on simplifying this setup, including reorganizing the folders, to avoid confusion with the old Redux structure. This way, during the internship, I won’t have to worry about where files or folders should go, and can focus on building efficiently.
  • Fix all performance issues in React detected by eslint-plugin-react-compiler.
  • One of the main areas I want to focus on is identifying whether frontend improvements (React + Redux with RTK Query) can further optimize endpoints that have already been improved on the backend. For example, I currently have a PR (#6287) that significantly improves the performance of the CoursesController#articles endpoint. However, I believe that with additional frontend optimization — specifically by using RTK Query and its infinite query capabilities — performance can be improved even further. I will follow this same pattern across other components to evaluate whether their frontend counterparts can be enhanced in a similar way.
  • Implement Prefetching for Course Tabs
    • To further enhance the user experience on course pages, I will implement prefetching for the JSON data used in other tabs (e.g., Articles, Students, Revisions, Activity). This will involve preloading relevant data while the user is on the main course page, so that when they click on a tab, the content appears instantly with zero perceived latency. Prefetching can be achieved using resource hints or RTK Query’s built-in prefetch method. This is a low-cost change with a meaningful impact on responsiveness.
  • Complete final enhancements to the backend and optimize Ruby code for improved performance.
  • Additionally, I will write detailed documentation explaining all the technical changes I made, along with the reasons behind each change, clearly outlining every step taken.

Participation

For communication, I primarily intend to use Slack, as it is the most convenient for real-time discussions. I will also be available via email and Zulip, as previously mentioned. I have already been in contact with my mentors Sage Ross and formasit prior to the start of the application period. Additionally, I am regularly active on GitHub and Slack, so I can promptly respond to any issues or discussions there. Throughout the coding period, I will be reachable on GitHub for any pull requests, issues, or feedback related to my contributions.

About Me

  • Education(Completed)
    • University: Nagaland University
    • Degree: Computer Science and Engineering
  • How did you hear about this program?
    • I heard about this program through youtube.
  • Will you have any other time commitments, such as school work, another job, planned vacation, etc, during the duration of the program?
    • Fully available throughout Outreachy 2025 with no planned vacations or employment conflicts. My most productive hours are 8:00 AM - 5:00PM IST on weekdays, with flexibility on weekends.
  • We advise all candidates eligible for Google Summer of Code and Outreachy to apply for both programs. Are you planning to apply to both programs and, if so, with what organization(s)?
    • No, I have not applied for GSOC, I have only applied for Outreachy 2025 with the wikimedia organization
  • What does making this project happen mean to you?
    • I began contributing to the Dashboard in late 2023 with the goal of applying my theoretical knowledge of computer science to real-world problems. Until then, most of my experience was academic, so I wanted to challenge myself by working on a live, user-facing project. Since then, I’ve had the opportunity to interact with past and current Dashboard interns, and I’ve learned a great deal from them especially from my mentor Sage Ross.One of the most rewarding moments has been hearing that some of my contributions bug fixes or new features have genuinely helped users of the Dashboard. At some point, solving bugs and tackling issues around the Dashboard started to feel like playing a video game I found myself really enjoying it, and I still do. Working on this project over the summer would feel like my way of giving back to the Dashboard, to the community, and especially to Sage and the past interns who’ve helped me grow. It would also allow me to contribute to some of the major issues I’ve been wanted to work on, and help take the Dashboard one step further in its development.

Past Experience

I have earned a great amount of experience with the codebase of the project over the past year and I’ve contributed to the dashboard over the past year or so.All of my contributions can be found here. Below I list some contributions which I made recently.

  • #6279(merged): Optimize Survey Recent Responses fetching to prevent N+1 queries
  • #6287(open): Optimize data loading for list of Articles edited in a Campaign, shown in Articles Edited tab
  • #6274(open): Optimize batching for updating outdated average views
  • #6204(open): Migrate Admin Notes CRUD from Redux to RTK Query & Set Up React-Redux Integration Testing

Flow Charts:

I have prepared two flowcharts — one for the backend and one for the frontend — which outline core strategies used to identify and resolve performance bottlenecks in the application, as shown below.

Front-end Flow

back end

Back-end Flow

back end

Event Timeline

Weekly Internship Report

Week 1: June 2 - June 6
Overview of Tasks Completed:

  • PR #6342 Minor Chore: Remove N+1 Query From Download Single Question Results CSV
  • Completed and refactored PR #6329 Locally to improve performance of survey results data loading, reducing page load time significantly.
  • Finalized PR #6343, optimizing Survey#course_for by eliminating N+1 queries and improving code clarity.
  • Investigated slow points in several controllers (e.g., CampaignController, RevisionFeedback)

Challenges faced:

  • Encountered multiple N+1 query issues requiring deep refactoring for clean, efficient code.
  • Ongoing difficulty accessing New Relic despite following documentation and attempting account changes.

Learnings and skills gained:

  • Improved understanding of performance optimization particularly around, garbage collections, memory usage, ActiveRecord and N+1 issues.
  • Gained experience in thoughtful refactoring and writing maintainable code

Weekly Internship Report

Week 2: June 9 - June 13
Overview of Tasks Completed:

  • Pushed refactored code for PRs #6348, #6343, and #6329.
  • Opened a GitHub issue to track open PRs.
  • Merged PRs #6356 and #6348.
  • Investigated and worked on N+1 issues in Survey Question Groups and Surveys tab.
  • Opened two new PRs (#6358 & #6360) addressing slow routes in survey endpoints.
  • Worked on CSV download and Survey#results endpoints, identifying need to split tasks for better review management.

Challenges faced:

  • Held off on opening PRs for some issues due to non-Rails implementation.
  • Spent significant time debugging N+1 query issues and learning about how custom methods can bypass Rails’ .includes.
  • Faced bugs while preparing the PR for survey Question Groups tab, causing delays.

Learnings and skills gained:

  • Improved understanding of .includes, ActiveRecord associations, and preloading mechanisms.
  • Gained insight into breaking down large refactors into manageable PRs.
  • Enhanced skills in debugging complex performance issues and writing optimized, review-friendly code.
  • Custom methods can bypass Rails’ .includes or totally ignoring rails preloaded association.

Weekly Internship Report

Week 3: June 16 – June 20
Overview of Tasks Completed:

  • Continued investigating and analyzing slow query logs(one out of four log files); identified one query's source and narrowed down search locations for the remaining ones from the first log file.
  • Used DebugBar and Rack Mini Profiler extensively on the local development to detect performance issues and unnecessary model loads.
  • Improved the performance of few P&E Dashboard routes.

PRs Merged:

  • Minor: Refactor training_modules method to improve query performance #6373
  • Chore: Fix minor N+1 in combined_wikidata_stats method #6372
  • Extract survey results logic into separate SurveyResultsController #6367
  • Optimize admin course loading for P&E Homepage by conditionally eager-loading students only for Wiki Ed #6366
  • Add link to download the CSV for each survey from results index page #6364
  • Optimize response method by preloading and grouping Rapidfire answers csv Download (PART 3) #6362
  • Optimize answer group retrieval to avoid N+1 queries with memoization For CSV download (PART 2) #6361
  • Chore: Fix very minor N+1 in surveys CSV download (PART 1) #6360
  • Optimize Question Group Rendering and Eliminate N+1 Queries #6358

Challenges Faced:

  • Tracking down the exact source of slow queries took time — especially confirming matches between logs and code patterns.
  • Debugging and confirming unnecessary model loads across many dashboard routes.

Learnings and Skills Gained:

  • Gained experience breaking down large features into smaller, reviewable PRs for smoother collaboration.

Weekly Internship Report

Week 4: June 23 – June 27

Overview of Tasks Completed:

  • Opened remaining PRs to improve database performance and clean up survey views.
  • Completed optimization work on survey results HTML, reducing load times across major views.
  • Resolved a performance issue where the Article query was not fully utilizing a composite index
  • Analyzed and identified sources of remaining slow queries from the four log files.
  • Investigated performance issues in CampaignsController#articles.

PRs Merged:

  • #6378: Optimize Article Lookup by Filtering Relevant Namespaces in Deletion Monitor
  • #6379: Optimize DiscretionarySanctionsMonitor Article Lookup by Adding Namespace Filter for Full Index Usage
  • #6380: Optimize Article Lookup in GANominationMonitor by Scoping Relevant Namespaces
  • #6381: Scope Article Lookup to Relevant Namespaces in HighQualityArticleMonitor
  • #6383: Optimize Survey Results Data Loading (PART 2): Refactor Answer and Answer Group Loading
  • #6385: Optimize Survey Results Data Loading (PART 3 FINAL): Streamline Answer Data Processing and View Queries
  • #6386: Minor Chore: Refactor Survey Question Results Components for Cleaner Props and Conditional Rendering

Challenges Faced:

  • None this week

Learnings and Skills Gained:

  • Deepened understanding of SQL performance optimization, particularly join behavior and index usage.
  • Learned to interpret slow query logs more accurately and spot performance patterns.

Weekly Internship Report

Week 5: June 30 – July 4

Overview of Tasks Completed:

  • Investigated multiple slow SQL queries from the slow log file and identified the source code responsible for most of them.
  • Focused on optimizing the CampaignsController#articles pagination. Deferred joins currently appear to be the most promising solution.
  • Identified a major slow query pattern related to missing namespace filtering and incomplete index usage, even after PR #6376. Found that although local results improved, production performance remained unchanged.
  • Traced the slow article_course_timeslices query to CourseCsvBuilder#revisions_by_namespace.

PRs merged:

  • Optimize Articles join using composite index in DYKNominationMonitor #6390

Challenges Faced:

  • Difficulty tracking down the source of certain JOIN-based slow queries due to variations in query structure.
  • Lack of performance improvement in production despite query refactoring — specifically due to not fully utilizing composite indexes (e.g., missing wiki_id in GROUP BY).
  • Limited data in local databases (e.g., empty article_course_timeslices table), making debugging and validation harder.

Learnings and Skills Gained:

  • Strengthened understanding of how SQL composite indexes work and how to write queries that fully leverage them.

Weekly Internship Report

Week 6: July 7 – July 11


Overview of Tasks Completed:

  • Implemented a deferred join for article pagination and tested it on a large dataset, improving performance.
  • Analyzed new slow queries from June's logs and began working on optimizations.

Challenges Faced:

  • Encountered multiple bugs during performance optimization and index tuning.
  • Query performance bottlenecks caused by combined filtering on indexed and non-indexed columns.

Learnings and Skills Gained:

  • Gained practical experience in performance profiling and how to use deferred joins in pagination.

Additional comments

  • Defined key goals for the rest of July:
    • Resolve all identified slow queries.
    • Improve the Wiki Diff Analyzer based on recent discussions.
    • Audit every route on the P\&E dashboard to ensure efficient data loading, leveraging tools like Bullet, Rack mini Profiler and Prospite.
    • Address performance issues reported in Sentry.
    • Work on writing a script to parse and analyze slow query logs efficiently.

Weekly Internship Report

Week 7: July 14 – July 18

Overview of Tasks Completed:

  1. Completed reviewing the entire slow query log for the P&E dashboard for the month of June.
    • 7 slow queries remain to be fixed from the June logs.
  1. Optimized the article_ids query by batching titles, helping prevent slowdowns caused by large IN clauses.
  1. Improved article batch performance by removing the DISTINCT dependency in SQL.
    • If distinctness is required, i think we can now handled it in Ruby enabling faster SQL execution.
  1. Worked on again optimizing the article count query for campaigns.
    • Since avoiding JOIN approach didn’t yield results, i tried adding an index on campaign_id in the campaigns_courses table which improved performance locally.However, i am worried that due to the low cardinality of campaign_id, this might not scale well in production.

Challenges Faced:

  1. Faced issues optimizing the article_course_timeslices query.
    • Adding a composite index didn’t help much in production, likely due to the low cardinality of both course_id and the associated tracked boolean field. This query is a priority, as it consistently appears in the slow query logs across multiple days from early to late June.

Learnings and Skills Gained:

  1. Learned that large IN clauses can significantly degrade query performance.
    • They can prevent the database from optimizing efficiently or using indexes.
    • Batching the IN conditions can greatly improve performance — in some cases, halving real time. (More details can be found in this PR)

Weekly Internship Report

Week 8: July 21 – July 25

Overview of Tasks Completed:

  1. Successfully resolved and merged PR #6424 – Optimize campaign articles using deferred join for pagination, after addressing a production issue related to the changes.
  1. Generated a proper benchmark for PR #6410 to validate that the changes provided a meaningful performance improvement.
  1. Identified the source code responsible for the slow query on the Courses homepage for course CSV stats report downloads.
    • The primary sources were CourseCsvBuilder#revisions_by_namespace and PerWikiCourseStats#wiki_stats.
  1. Developed and finalized solutions for the remaining 4 slow queries from the June slow query logs.

Challenges Faced:

  1. A production issue occurred after merging PR #6402, due to a dependency loading error.
    • It took some investigation to trace and fix the issue, as it wasn’t apparent during development or testing.

Learnings and Skills Gained:

  1. Learned that Zeitwerk autoloading can lead to production errors when constant names don’t match file paths — especially if eager loading is disabled during development and tests.
    • In development, eager loading is often turned off to speed up test execution, but this can hide critical loading issues.
    • A helpful practice is to run locally or add an autoloading consistency check in github CI using:
      • bundle exec rails runner "Rails.application.eager_load!"

Weekly Internship Report

Week 9: July 28 – August 1


Overview of Tasks Completed:
  1. Optimized Articles Count Query Improved the performance of the articles count query by adding an index on campaign_id in the campaigns_courses table. This significantly reduced query time by avoiding unnecessary joins. There is still work left in this which I plan to do next week.
  1. Optimized CSV Generation Refactored CourseCsvBuilder#revisions_by_namespace to perform the SUM operation directly in the database rather than in Ruby. This lowered memory usage and improved response time.
  1. Improved PerWikiCourseStats Performance
    • Part 1: Addressed initial performance bottlenecks in PerWikiCourseStats#wiki_stats.
    • Part 2: Continued optimizations to further reduce query time and improve data handling.
  1. Enhanced Test Coverage Added test cases for the updated logic in PR #6424 – Optimize campaign articles using deferred join for pagination (v2). This was necessary to detect and prevent caching-related issues during local development and CI runs.

Challenges Faced:

  • None this week

Learnings and Skills Gained:

  • Learned a bit of RSpec, as it was needed to write a test case for PR #6430.

Weekly Internship Report

Week 10: August 4 - August 8


Overview of Tasks Completed:

  1. PR #6439 Improve performance of PerWikiCourseStats#stats
  2. PR #6442 Remove N+1 queries in IndividualStatisticsTimeslicePresenter#course_user_records
  3. PR #6444 Remove N+1 queries in IndividualStatisticsTimeslicePresenter#article_course_records
  4. Was finally able to resolve PR #6388. The new updates are posted here.

Challenges Faced:

  1. None this week.

Learning and Skills Gained:

  1. None this week.

Weekly Internship Report

Week 11: August 11 - August 15


Overview of Tasks Completed:
  1. PR #6449 Remove N+1 queries in IndividualStatisticsTimeslicePresenter#set_upload_usage_counts
  1. PR #6451 Refactor CoursesPresenter to use shared campaign_articles_count helper
  1. PR #6452 Optimize campaign course statistics by consolidating multiple queries into single database call
  1. PR #6453 Optimize duplicate article deletion by batching title queries

Challenges Faced:
  1. I have not yet found an optimized approach to improve the performance of PR #6404 – Optimize article_course_timeslices queries by adding a composite index on course_id and tracked.

Learning and Skills Gained:
  1. Learned about the difference between web server deployments and Sidekiq process deployments.
  1. Improved my understanding of Capistrano deployment configurations, how Sidekiq processes are restarted, and why queries optimized in PRs may not take effect for Sidekiq until Sidekiq is redeployed.

Weekly Internship Report

Week 12: August 18 - August 22


Overview of Tasks Completed:
  1. Started working on improving the performance for wikidata-diff-analyzer which is a Ruby gem for extracting information for Wikidata edits.
  1. Also, working on

Challenges Faced:
  1. None this week.

Learning and Skills Gained:
  1. None this week.

Here's a nice visualization of the progress we made on performance problems since the start of the internship, in the form of the downtime monitor for Programs & Events Dashboard.

uptime progress.png (177×2 px, 15 KB)

It looks like we finally have the downtime under control!

Weekly Internship Report

Week 13: August 25 - August 29


Overview of Tasks Completed:
  • Went through the wiki-diff-analyzer gem to check if any further improvements could be made. The gem is already well-optimized, and all the code runs and responds within the expected response time. So, there isn’t much to improve here.

Challenges Faced:
  • This week(13), I was going through the wiki-diff-analyzer gem. Since it was my first time exploring a Ruby gem codebase in detail, I found it a bit challenging to understand how it connects and interacts with the main Dashboard codebase. Mapping the flow between the gem and its usage in the application took more time then I expected.

Learning and Skills Gained:
  • So while going through the wiki-diff-analyzer gem, I learned how a Ruby gem is structured and set up, and how it integrates into a larger codebase. This gave me a clearer understanding of working with external libraries—specifically how Ruby gems are organized, why we would want to build a gem instead of writing everything directly in the main codebase, and how to trace their usage within an application.

Performance Improvement (June 1 – August 29):

The uptime graph (Jun 1 - August 29) below reflects the results of improvements for Programs & Events Dashboard.

Uptime Graph.png (124×1 px, 13 KB)

  • Initial State (June 1): The system experienced frequent downtimes, shown by the red segments in the graph.
  • Improvements Applied: Over the course of the internship, I worked on performance fixes and optimizations that addressed slow queries and system bottlenecks.
  • Current State (August 11 - 29): The system now shows significantly improved stability, with very few interruptions compared to the start of the period.
  • All the pull requests I worked on and that were merged during the internship period are documented under this main tracking issue: Outreachy (Round 30): Improve performance of slow routes in Programs & Events Dashboard #6352.

These results indicate that the changes and pull requests made during my internship had a positive impact on the reliability , responsiveness and downtime of the dashboard is now under control.