{"id":78344,"date":"2024-06-11T10:00:33","date_gmt":"2024-06-11T17:00:33","guid":{"rendered":"https:\/\/github.blog\/?p=78344"},"modified":"2024-07-23T06:11:43","modified_gmt":"2024-07-23T13:11:43","slug":"how-we-improved-push-processing-on-github","status":"publish","type":"post","link":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/","title":{"rendered":"How we improved push processing on GitHub"},"content":{"rendered":"<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\">\n<html><body><p>What happens when you <a href=\"https:\/\/github.blog\/2024-06-10-top-12-git-commands-every-developer-must-know\/\">push to GitHub<\/a>? The answer, &ldquo;My repository gets my changes&rdquo; or maybe, &ldquo;The refs on my remote get updated&rdquo; is pretty much right&mdash;and that is a really important thing that happens, but there&rsquo;s a whole lot more that goes on after that. To name a few examples:<\/p>\n<ul>\n<li>Pull requests are synchronized, meaning the diff and commits in your pull request reflect your newly pushed changes.<\/li>\n<li>Push webhooks are dispatched.<\/li>\n<li>Workflows are triggered.<\/li>\n<li>If you push an app configuration file (like for Dependabot or GitHub Actions), the app is automatically installed on your repository.<\/li>\n<li>GitHub Pages are published.<\/li>\n<li>Codespaces configuration is updated.<\/li>\n<li>And much, much more.<\/li>\n<\/ul>\n<p>Those are some pretty important things, and this is just a sample of what goes on for every push. In fact, in the GitHub monolith, there are over 60 different pieces of logic owned by 20 different services that run in direct response to a push. That&rsquo;s actually really cool&mdash;we <em>should<\/em> be doing a bunch of interesting things when code gets pushed to GitHub. In some sense, that&rsquo;s a big part of what GitHub is, the place you push code<sup id=\"fnref-78344-1\"><a href=\"#fn-78344-1\" class=\"jetpack-footnote\" title=\"Read footnote.\">1<\/a><\/sup> and then cool stuff happens.<\/p>\n<h2 id=\"the-problem\" id=\"the-problem\" ><a class=\"heading-link\" href=\"#the-problem\">The problem<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>What&rsquo;s not so cool is that, up until recently, all of these things were the responsibility of a single, enormous background job. Whenever GitHub&rsquo;s Ruby on Rails monolith was notified of a push, it enqueued a massive job called the <code>RepositoryPushJob<strong>. <\/strong><\/code>This job was the home for all push processing logic, and its size and complexity led to many problems. The job triggered one thing after another in a long, sequential series of steps, kind of like this:<\/p>\n<p><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png\"><img data-recalc-dims=\"1\" decoding=\"async\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png?w=1024&#038;resize=1024%2C244\" alt='A flow chart from left to right. The first step is \"Push\". Then second step is \"GitHub Rails monolith\". The third step is a large block labeled \"RepositoryPushJob\" which contains a sequence of steps inside it. These steps are: \"Apps callback\", \"Codespaces callback\", \"PRs callback\", followed by a callout that there are 50+ tasks after this one. The final step is \"processing task n\". ' width=\"1024\" height=\"244\" class=\"aligncenter size-large wp-image-78346 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png?w=1600 1600w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png?w=1024 1024w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-original.png?w=1536 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><\/p>\n<p>There are a few things wrong with this picture. Let&rsquo;s highlight some of them:<\/p>\n<ul>\n<li><strong>This job was huge, and hard to retry.<\/strong> The size of the <code>RepositoryPushJob<\/code> made it very difficult for different push processing tasks to be retried correctly. On a retry, all the logic of the job is repeated from the beginning, which is not always appropriate for individual tasks. For example:\n<ul>\n<li>Writing <code>Push<\/code> records to the database can be retried liberally on errors and reattempted any amount of time after the push, and will gracefully handle duplicate data. <\/li>\n<li>Sending push webhooks, on the other hand, is much more time-sensitive and should not be reattempted too long after the push has occurred. It is also not desirable to dispatch multiples of the <em>same<\/em> webhook. <\/li>\n<\/ul>\n<\/li>\n<li><strong>Most of these steps were never retried at all.<\/strong> The above difficulties with conflicting retry concerns ultimately led to retries of <code>RepositoryPushJob<\/code> being avoided in most cases. To prevent one step from killing the entire job, however, much of the push handling logic was wrapped in code catching any and all errors. This lack of retries led to issues where crucial pieces of push processing never occurred.<\/li>\n<li><strong>Tight coupling of many concerns created a huge blast radius for problems.<\/strong> While most of the dozens of tasks in this job rescued all errors, for historical reasons, a few pieces of work in the beginning of the job did not. This meant that all of the later steps had an implicit dependency on the initial parts of the job. As more concerns are combined within the same job, the likelihood of errors impacting the entire job increases.\n<ul>\n<li>For example, writing data to our <code>Pushes<\/code> MySQL cluster occurred in the beginning of the <code>RepositoryPushJob<\/code>. This meant that everything occurring after that had an implicit dependency on this cluster. This structure led to incidents where errors from this database cluster meant that user pull requests were not synchronized, even though pull requests have no explicit need to connect to this cluster.<\/li>\n<\/ul>\n<\/li>\n<li><strong>A super long sequential process is bad for latency.<\/strong> It&rsquo;s fine for the first few steps, but what about the things that happen last? They have to wait for every other piece of logic to run before they get a chance. In some cases, this structure led to a second or more of unnecessary latency for user-facing push tasks, including pull request synchronization. <\/li>\n<\/ul>\n<h2 id=\"what-did-we-do-about-this\" id=\"what-did-we-do-about-this\" ><a class=\"heading-link\" href=\"#what-did-we-do-about-this\">What did we do about this?<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>At a high level, we took this very long sequential process and decoupled it into many isolated, parallel processes. We used the following approach:<\/p>\n<ul>\n<li>We added a new Kafka topic that we publish an event to for each push.<\/li>\n<li>We examined each of the many push processing tasks and grouped them by owning service and\/or logical relationships (for example, order dependency, retry-ability).<\/li>\n<li>For each coherent group of tasks, we placed them into a new background job with a clear owner and appropriate retry configuration. <\/li>\n<li>Finally, we configured these jobs to be enqueued for each publish of the new Kafka event.\n<ul>\n<li>To do this, we used an internal system at GitHub that facilitates enqueueing background jobs in response to Kafka events via independent consumers. <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>We had to make investments in several areas to support this architecture, including:<\/p>\n<ul>\n<li>Creating a reliable publisher for our Kafka event&ndash;one that would retry until broker acknowledgement. <\/li>\n<li>Setting up a dedicated pool of job workers to handle the new job queues we&rsquo;d need for this level of fan out.<\/li>\n<li>Improving observability to ensure we could carefully monitor the flow of push events throughout this pipeline and detect any bottlenecks or problems. <\/li>\n<li>Devising a system for consistent per-event feature flagging, to ensure that we could gradually roll out (and roll back if needed) the new system without risk of data loss or double processing of events between the old and new pipelines. <\/li>\n<\/ul>\n<p>Now, things look like this:<\/p>\n<p><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png\"><img data-recalc-dims=\"1\" decoding=\"async\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png?w=1024&#038;resize=1024%2C822\" alt='A flow chart from left to right. The first step is \"Push\". The second step is \"GitHub Rails monolith\". The connection between the second and third step is labeled \"Push event\". The third step is \"Kafka\". The fourth step is \"Kafka to job queue bridge\". Then, there are 16 parallel connectors branching out from the fourth step to the next steps. These are: \"AppsOnPushJob\", \"CodespacesOnPushJob\", \"PullRequestsOnPushJob\", \"MarketPlaceOnPushJob\", \"ProjectStackOnPushJob\", \"SecurityCenterPushJob\", \"IssuesOnPushJob\", \"PagesOnPushJob\", \"MaintenanceOnPushJob\", \"NotificationsOnPushJob\", \"RepositoriesOnPushJob\", \"ReleasesOnPushJob\", \"ActionsOnPushJob\", \"WikisOnPushJob\", \"SearchOnPushJob\", and \"Push job n\".' width=\"1024\" height=\"822\" class=\"aligncenter size-large wp-image-78347 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png?w=1600 1600w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png?w=1024 1024w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/push-processing-improved.png?w=1536 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><\/p>\n<p>A push triggers a Kafka event, which is fanned out via independent consumers to many isolated jobs that can process the event without worrying about any <em>other<\/em> consumers.<\/p>\n<h2 id=\"results\" id=\"results\" ><a class=\"heading-link\" href=\"#results\">Results<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<ul>\n<li><strong>A smaller blast radius for problems.<\/strong>\n<ul>\n<li>This can be clearly seen from the diagram. Previously, an issue with a single step in the very long push handling process could impact everything downstream. Now, issues with one piece of push handling logic don&rsquo;t have the ability to take down much else. <\/li>\n<li>Structurally, this decreases the risk of dependencies. For example, there are around 300 million push processing operations executed per day in the new pipeline that previously implicitly depended on the <code>Pushes<\/code> MySQL cluster and now have no such dependency, simply as a product of being moved into isolated processes. <\/li>\n<li>Decoupling also means better ownership. In splitting up these jobs, we distributed ownership of the push processing code from one owning team to 15+ more appropriate service owners. New push functionality in our monolith can be added and iterated on by the owning team without unintentional impact to other teams.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Pushes are processed with lower latency.<\/strong>\n<ul>\n<li>By running these jobs in parallel, no push processing task has to wait for others to complete. This means better latency for just about everything that happens on push. <\/li>\n<li>For example, we can see a notable decrease in pull request sync time:<\/li>\n<\/ul>\n<p><a href=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/pull-request-sync-time.png\"><img data-recalc-dims=\"1\" decoding=\"async\" loading=\"lazy\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/pull-request-sync-time.png?w=1024&#038;resize=1024%2C510\" alt=\"A line chart depicting the p50 pull request sync time since head ref update over several previous months. The line hovers around 3 seconds from September 2023 through November 2023. In December 2023, it drops to around 2 seconds. \" width=\"1024\" height=\"510\" class=\"aligncenter size-large wp-image-78348 width-fit\" srcset=\"https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/pull-request-sync-time.png?w=1238 1238w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/pull-request-sync-time.png?w=300 300w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/pull-request-sync-time.png?w=768 768w, https:\/\/github.blog\/wp-content\/uploads\/2024\/06\/pull-request-sync-time.png?w=1024 1024w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><\/p>\n<\/li>\n<li>\n<p><strong>Improved observability.<\/strong><\/p>\n<ul>\n<li>By breaking things up into smaller jobs, we get a much clearer picture of what&rsquo;s going on with each job. This lets us set up observability and monitoring that is much more finely scoped than anything we had before, and helps us to quickly pinpoint any problems with pushes.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Pushes are more reliably processed.<\/strong>\n<ul>\n<li>By reducing the size and complexity of the jobs that process pushes, we are able to retry <em>more<\/em> things than in the previous system. Each job can have retry configuration that&rsquo;s appropriate for its own small set of concerns, without having to worry about re-executing other, unrelated logic on retry. <\/li>\n<li>If we define a &ldquo;fully processed&rdquo; push as a push event for which <em>all<\/em> the desired operations are completed with no failures, the old <code>RepositoryPushJob<\/code> system fully processed about <strong>99.897%<\/strong> of pushes.<\/li>\n<li>In the worst-case estimate, the new pipeline fully processes <strong>99.999%<\/strong> of pushes.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2 id=\"conclusion\" id=\"conclusion\" ><a class=\"heading-link\" href=\"#conclusion\">Conclusion<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h2>\n<p>Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. It&rsquo;s important that our system handles everyone&rsquo;s pushes reliably and efficiently, and over the past several months we have significantly improved the ability of our monolith to correctly and fully process pushes from our users. Through platform level investments like this one, we strive to make GitHub the home for all developers (and their many pushes!) far into the future.<\/p>\n<p><!-- Footnotes themselves at the bottom. --><\/p>\n<h4 id=\"notes\" id=\"notes\" ><a class=\"heading-link\" href=\"#notes\">Notes<span class=\"heading-hash pl-2 text-italic text-bold\" aria-hidden=\"true\"><\/span><\/a><\/h4>\n<div class=\"footnotes\">\n<hr>\n<ol>\n<li id=\"fn-78344-1\">\nPeople push to GitHub a whole lot, as you can imagine. In the last 30 days, we&rsquo;ve received around 500 million pushes from 8.5 million users.&nbsp;<a href=\"#fnref-78344-1\" title=\"Return to main content.\">&#8617;<\/a>\n<\/li>\n<\/ol>\n<\/div>\n<\/body><\/html>\n","protected":false},"excerpt":{"rendered":"<p>Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.<\/p>\n","protected":false},"author":2239,"featured_media":75860,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_gh_post_show_toc":"yes","_gh_post_is_no_robots":"no","_gh_post_is_featured":"no","_gh_post_is_excluded":"no","_gh_post_is_unlisted":"no","_gh_post_related_link_1":"","_gh_post_related_link_2":"","_gh_post_related_link_3":"","_gh_post_sq_img":"","_gh_post_sq_img_id":"","_gh_post_cta_title":"","_gh_post_cta_text":"","_gh_post_cta_link":"","_gh_post_cta_button":"Click Here to Learn More","_gh_post_recirc_hide":"no","_gh_post_recirc_col_1":"gh-auto-select","_gh_post_recirc_col_2":"77524","_gh_post_recirc_col_3":"65303","_gh_post_recirc_col_4":"65316","_featured_video":"","_gh_post_additional_query_params":"","_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"_links_to":"","_links_to_target":""},"categories":[3307,72],"tags":[2944],"coauthors":[3287],"class_list":["post-78344","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-architecture-optimization","category-engineering","tag-how-github-builds-github"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How we improved push processing on GitHub - The GitHub Blog<\/title>\n<meta name=\"description\" content=\"Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How we improved push processing on GitHub\" \/>\n<meta property=\"og:description\" content=\"Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/\" \/>\n<meta property=\"og:site_name\" content=\"The GitHub Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-06-11T17:00:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-07-23T13:11:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Will Haltom\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Will Haltom\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/\"},\"author\":{\"name\":\"Will Haltom\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/78fd514c4c7249b3365f82a8f9bb5234\"},\"headline\":\"How we improved push processing on GitHub\",\"datePublished\":\"2024-06-11T17:00:33+00:00\",\"dateModified\":\"2024-07-23T13:11:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/\"},\"wordCount\":1405,\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/Productivity-DarkMode-2-1.png?fit=1200%2C630\",\"keywords\":[\"How GitHub builds GitHub\"],\"articleSection\":[\"Architecture &amp; optimization\",\"Engineering\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/\",\"url\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/\",\"name\":\"How we improved push processing on GitHub - The GitHub Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/Productivity-DarkMode-2-1.png?fit=1200%2C630\",\"datePublished\":\"2024-06-11T17:00:33+00:00\",\"dateModified\":\"2024-07-23T13:11:43+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/78fd514c4c7249b3365f82a8f9bb5234\"},\"description\":\"Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#primaryimage\",\"url\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/Productivity-DarkMode-2-1.png?fit=1200%2C630\",\"contentUrl\":\"https:\\\/\\\/github.blog\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/Productivity-DarkMode-2-1.png?fit=1200%2C630\",\"width\":1200,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/how-we-improved-push-processing-on-github\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/github.blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Engineering\",\"item\":\"https:\\\/\\\/github.blog\\\/engineering\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Architecture &amp; optimization\",\"item\":\"https:\\\/\\\/github.blog\\\/engineering\\\/architecture-optimization\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"How we improved push processing on GitHub\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/github.blog\\\/#website\",\"url\":\"https:\\\/\\\/github.blog\\\/\",\"name\":\"The GitHub Blog\",\"description\":\"Updates, ideas, and inspiration from GitHub to help developers build and design software.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/github.blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/github.blog\\\/#\\\/schema\\\/person\\\/78fd514c4c7249b3365f82a8f9bb5234\",\"name\":\"Will Haltom\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4a771219db9ab6ee1a0fa46e4bdf7fdbc9e5f5ba92438235fc3522679adbf054?s=96&d=mm&r=gfe4e28facc4dac7be06354b8515224a7\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4a771219db9ab6ee1a0fa46e4bdf7fdbc9e5f5ba92438235fc3522679adbf054?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4a771219db9ab6ee1a0fa46e4bdf7fdbc9e5f5ba92438235fc3522679adbf054?s=96&d=mm&r=g\",\"caption\":\"Will Haltom\"},\"url\":\"https:\\\/\\\/github.blog\\\/author\\\/willhalto\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How we improved push processing on GitHub - The GitHub Blog","description":"Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/","og_locale":"en_US","og_type":"article","og_title":"How we improved push processing on GitHub","og_description":"Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.","og_url":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/","og_site_name":"The GitHub Blog","article_published_time":"2024-06-11T17:00:33+00:00","article_modified_time":"2024-07-23T13:11:43+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630","type":"image\/png"}],"author":"Will Haltom","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Will Haltom","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#article","isPartOf":{"@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/"},"author":{"name":"Will Haltom","@id":"https:\/\/github.blog\/#\/schema\/person\/78fd514c4c7249b3365f82a8f9bb5234"},"headline":"How we improved push processing on GitHub","datePublished":"2024-06-11T17:00:33+00:00","dateModified":"2024-07-23T13:11:43+00:00","mainEntityOfPage":{"@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/"},"wordCount":1405,"image":{"@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630","keywords":["How GitHub builds GitHub"],"articleSection":["Architecture &amp; optimization","Engineering"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/","url":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/","name":"How we improved push processing on GitHub - The GitHub Blog","isPartOf":{"@id":"https:\/\/github.blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#primaryimage"},"image":{"@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#primaryimage"},"thumbnailUrl":"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630","datePublished":"2024-06-11T17:00:33+00:00","dateModified":"2024-07-23T13:11:43+00:00","author":{"@id":"https:\/\/github.blog\/#\/schema\/person\/78fd514c4c7249b3365f82a8f9bb5234"},"description":"Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.","breadcrumb":{"@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#primaryimage","url":"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630","contentUrl":"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630","width":1200,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/github.blog\/engineering\/architecture-optimization\/how-we-improved-push-processing-on-github\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/github.blog\/"},{"@type":"ListItem","position":2,"name":"Engineering","item":"https:\/\/github.blog\/engineering\/"},{"@type":"ListItem","position":3,"name":"Architecture &amp; optimization","item":"https:\/\/github.blog\/engineering\/architecture-optimization\/"},{"@type":"ListItem","position":4,"name":"How we improved push processing on GitHub"}]},{"@type":"WebSite","@id":"https:\/\/github.blog\/#website","url":"https:\/\/github.blog\/","name":"The GitHub Blog","description":"Updates, ideas, and inspiration from GitHub to help developers build and design software.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/github.blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/github.blog\/#\/schema\/person\/78fd514c4c7249b3365f82a8f9bb5234","name":"Will Haltom","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/4a771219db9ab6ee1a0fa46e4bdf7fdbc9e5f5ba92438235fc3522679adbf054?s=96&d=mm&r=gfe4e28facc4dac7be06354b8515224a7","url":"https:\/\/secure.gravatar.com\/avatar\/4a771219db9ab6ee1a0fa46e4bdf7fdbc9e5f5ba92438235fc3522679adbf054?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4a771219db9ab6ee1a0fa46e4bdf7fdbc9e5f5ba92438235fc3522679adbf054?s=96&d=mm&r=g","caption":"Will Haltom"},"url":"https:\/\/github.blog\/author\/willhalto\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/github.blog\/wp-content\/uploads\/2023\/12\/Productivity-DarkMode-2-1.png?fit=1200%2C630","jetpack_shortlink":"https:\/\/wp.me\/pamS32-knC","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/78344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/users\/2239"}],"replies":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/comments?post=78344"}],"version-history":[{"count":3,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/78344\/revisions"}],"predecessor-version":[{"id":78350,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/posts\/78344\/revisions\/78350"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media\/75860"}],"wp:attachment":[{"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/media?parent=78344"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/categories?post=78344"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/tags?post=78344"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/github.blog\/wp-json\/wp\/v2\/coauthors?post=78344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}