Skip to content

Commit

Permalink
feat(pq): use accept-encoding: gzip when downloading PQL chunks (#4622
Browse files Browse the repository at this point in the history
)

The server that serves chunks support `accept-encoding: gzip` (and in
fact, the chunks are currently stored GZIPped so getting them compressed
is a server-side no-op) but we forgot to enable compressed streaming
when originally writing the manifest polling code.

In order to use reqwest's auto-gzip feature, you have to enable the gzip
feature on the crate, and this also turns it on by default. While it's
likely that this is a beneficial feature in other parts of Router, I did
my best to disable it in all other uses of reqwest in apollo-router that
I could find. (If nothing else, this was necessary to fix the
`it_compress_response_body` test which uses a reqwest::Client to make
sure that Router returns compressed bodies properly.)

Co-authored-by: Geoffroy Couprie <apollo@geoffroycouprie.com>
Co-authored-by: Coenen Benjamin <benjamin.coenen@hotmail.com>
  • Loading branch information
3 people committed Feb 22, 2024
1 parent 4925ec9 commit 05a651d
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changesets/feat_glasser_pq_gzip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Use gzip compression when downloading Persisted Query manifests

Router will now request gzip compression when downloading Persisted Query manifests for improved network efficiency.

By [@glasser](https://github.com/glasser) in https://github.com/apollographql/router/pull/4622
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5437,6 +5437,7 @@ version = "0.11.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
dependencies = [
"async-compression",
"base64 0.21.7",
"bytes",
"encoding_rs",
Expand Down
1 change: 1 addition & 0 deletions apollo-router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ regex = "1.10.3"
reqwest = { version = "0.11.24", default-features = false, features = [
"rustls-tls",
"rustls-native-certs",
"gzip",
"json",
"stream",
] }
Expand Down
2 changes: 2 additions & 0 deletions apollo-router/src/axum_factory/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ async fn init(
);

let client = reqwest::Client::builder()
.no_gzip()
.default_headers(default_headers)
.redirect(Policy::none())
.build()
Expand Down Expand Up @@ -289,6 +290,7 @@ pub(super) async fn init_with_config(
);

let client = reqwest::Client::builder()
.no_gzip()
.default_headers(default_headers)
.redirect(Policy::none())
.build()
Expand Down
1 change: 1 addition & 0 deletions apollo-router/src/plugins/telemetry/apollo_exporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ impl ApolloExporter {
batch_config: batch_config.clone(),
apollo_key: apollo_key.to_string(),
client: reqwest::Client::builder()
.no_gzip()
.timeout(batch_config.max_export_timeout)
.build()
.map_err(BoxError::from)?,
Expand Down
1 change: 1 addition & 0 deletions apollo-router/src/router/event/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ impl Fetcher {
fn new(urls: Vec<Url>, period: Duration) -> Result<Self, FetcherError> {
Ok(Self {
client: reqwest::Client::builder()
.no_gzip()
.timeout(Duration::from_secs(10))
.build()
.map_err(FetcherError::InitializationError)?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl PersistedQueryManifestPoller {
freeform_graphql_behavior: FreeformGraphQLBehavior::DenyAll { log_unknown: false },
}));

let http_client = Client::builder().timeout(uplink_config.timeout).build()
let http_client = Client::builder().timeout(uplink_config.timeout).gzip(true).build()
.map_err(|e| -> BoxError {
format!(
"could not initialize HTTP client for fetching persisted queries manifest chunks: {}",
Expand Down
17 changes: 15 additions & 2 deletions apollo-router/src/test_harness/mocks/persisted_queries.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::collections::HashMap;
use std::time::Duration;

use async_compression::tokio::write::GzipEncoder;
use maplit::hashmap;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use tokio::io::AsyncWriteExt;
use url::Url;
use wiremock::matchers::header;
use wiremock::matchers::method;
use wiremock::Mock;
use wiremock::MockServer;
Expand Down Expand Up @@ -75,13 +78,23 @@ pub async fn mock_pq_uplink_one_endpoint(

let mock_gcs_server = MockServer::start().await;

let gcs_response = ResponseTemplate::new(200).set_body_json(json!({
let body_json = serde_json::to_vec(&json!({
"format": "apollo-persisted-query-manifest",
"version": 1,
"operations": operations
}));
}))
.expect("Failed to convert into body.");
let mut encoder = GzipEncoder::new(Vec::new());
encoder.write_all(&body_json).await.unwrap();
encoder.shutdown().await.unwrap();
let compressed_body = encoder.into_inner();

let gcs_response = ResponseTemplate::new(200)
.set_body_raw(compressed_body, "application/octet-stream")
.append_header("Content-Encoding", "gzip");

Mock::given(method("GET"))
.and(header("Accept-Encoding", "gzip"))
.respond_with(gcs_response)
.mount(&mock_gcs_server)
.await;
Expand Down
1 change: 1 addition & 0 deletions apollo-router/src/uplink/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ where
let query = query_name::<Query>();
let (sender, receiver) = channel(2);
let client = match reqwest::Client::builder()
.no_gzip()
.timeout(uplink_config.timeout)
.build()
{
Expand Down

0 comments on commit 05a651d

Please sign in to comment.