Skip to content
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

Router generation of sig and refs for apollo reporting #4796

Merged
merged 59 commits into from
Apr 12, 2024

Conversation

bonnici
Copy link
Contributor

@bonnici bonnici commented Mar 13, 2024

This PR introduces experimental support for generating the stats report key (signature) and referenced fields in native rust code instead of using what is generated by router-bridge as part of query planning. There were a number of gotchas that I found in the JS code that I have faithfully ported across, but at this point I've run enough unit tests and fuzz testing that I'm confident it's generating the same as the JS code.

Any comments related to Rust code conventions etc are very welcome as I haven't written much Rust code before.

Some specific questions I have:

  • Should I keep this in a separate crate or move the functionality to a public function within the router crate? It was originally moved to a separate crate because we thought it would be necessary to be able to run the fuzz tests, but we should be able to do that with a public function.
  • Are the auto-generated updates to the licence ok? I'm not sure how to validate that
  • Is there anything else I should test? Should I try to do some benchmarking? Should I run this through our corpus tests?

Implements https://apollographql.atlassian.net/browse/FED-117.


Checklist

Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.

  • Changes are compatible1
  • Documentation2 completed
  • Performance impact assessed and acceptable
  • Tests added and passing3
    • Unit Tests
    • Integration Tests
    • Manual Tests

Exceptions

Note any exceptions here

Notes

Footnotes

  1. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.

  2. Configuration is an important part of many changes. Where applicable please try to document configuration examples.

  3. Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions.

@router-perf
Copy link

router-perf bot commented Mar 13, 2024

CI performance tests

  • reload - Reload test over a long period of time at a constant rate of users
  • events_big_cap_high_rate_callback - Stress test for events with a lot of users, deduplication enabled and high rate event with a big queue capacity using callback mode
  • events_without_dedup_callback - Stress test for events with a lot of users and deduplication DISABLED using callback mode
  • large-request - Stress test with a 1 MB request payload
  • const - Basic stress test that runs with a constant number of users
  • no-graphos - Basic stress test, no GraphOS.
  • step-jemalloc-tuning - Clone of the basic stress test for jemalloc tuning
  • events - Stress test for events with a lot of users and deduplication ENABLED
  • events_callback - Stress test for events with a lot of users and deduplication ENABLED in callback mode
  • events_big_cap_high_rate - Stress test for events with a lot of users, deduplication enabled and high rate event with a big queue capacity
  • events_without_dedup - Stress test for events with a lot of users and deduplication DISABLED
  • xxlarge-request - Stress test with 100 MB request payload
  • xlarge-request - Stress test with 10 MB request payload
  • step - Basic stress test that steps up the number of users over time

format!("# {}\n{}", operation_name, stripped_body)
}

// todo move this somewhere else? somewhere where it's possible to do fuzzing?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps the operation signature can just live in its own small crate in the router workspace? we don't have to publish it. it would allow this to be called from the fuzz crate in the router.

@Geal were there any previous discussions in the router that would not allow for there to be a new workspace crate?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do publish https://crates.io/crates/apollo-router for Rust plugins, so its dependencies need to be published as well. Would https://github.com/apollographql/federation-next/ / https://crates.io/crates/apollo-federation be a good place for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this functionality belongs with federation at all, it feels so much closer to how the router itself interops with studio. At that point I'd rather have this as a published crate in the router's repository?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That follows the pattern of the JS libraries too. The functionality I'm porting in this PR is in the https://github.com/apollographql/apollo-utils repo, not the federation repo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lrlna I don't think I can put this code into a separate crate. It has dependencies on some classes/structs in the router crate like ParsedDocument and ReferencedFieldsForType so if I used it in its own crate I think there would be a circular dependency between apollo-router and this new interop crate?

If I just move the code to a public function in the apollo-router crate, can I set up the fuzzer to call that?

Copy link
Contributor Author

@bonnici bonnici Mar 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a little while to figure it out how to do that but I've done it now and I ran into a very odd dependency issue. When I try to run the fuzzer using

cargo +nightly fuzz run apollo_router_studio_interop

I get the error

error[E0635]: unknown feature `stdsimd`
  --> /Users/nickmarsh/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ahash-0.8.6/src/lib.rs:99:42
   |
99 | #![cfg_attr(feature = "stdsimd", feature(stdsimd))]

Apparently this is because of a transitive dependency to ahash and we'd need to upgrade from v0.8.6 to v0.8.7, but the dependency chain is very complicated. Any thoughts on how I can resolve this?

Dependency chain
❯ cargo tree -i ahash
ahash v0.8.6
├── hashbrown v0.14.1
│   ├── dashmap v5.5.3
│   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   └── serial_test v3.0.0
│   │       [dev-dependencies]
│   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   ├── indexmap v2.2.3
│   │   ├── apollo-compiler v1.0.0-beta.13
│   │   │   ├── apollo-federation v0.0.8
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   ├── apollo-federation v0.0.8 (*)
│   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   ├── h2 v0.3.24
│   │   │   ├── aws-smithy-runtime v1.1.6
│   │   │   │   ├── aws-config v1.1.6
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── aws-sdk-sso v1.14.0
│   │   │   │   │   └── aws-config v1.1.6 (*)
│   │   │   │   ├── aws-sdk-ssooidc v1.14.0
│   │   │   │   │   └── aws-config v1.1.6 (*)
│   │   │   │   └── aws-sdk-sts v1.14.0
│   │   │   │       └── aws-config v1.1.6 (*)
│   │   │   ├── hyper v0.14.28
│   │   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── aws-config v1.1.6 (*)
│   │   │   │   ├── aws-smithy-runtime v1.1.6 (*)
│   │   │   │   ├── axum v0.6.20
│   │   │   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   └── tonic v0.9.2
│   │   │   │   │       ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       ├── opentelemetry-otlp v0.13.0
│   │   │   │   │       │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       └── opentelemetry-proto v0.3.0
│   │   │   │   │           └── opentelemetry-otlp v0.13.0 (*)
│   │   │   │   │   [dev-dependencies]
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── hyper-rustls v0.24.2
│   │   │   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   ├── aws-smithy-runtime v1.1.6 (*)
│   │   │   │   │   └── reqwest v0.11.24
│   │   │   │   │       ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       ├── opentelemetry-datadog v0.8.0
│   │   │   │   │       │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       ├── opentelemetry-http v0.9.0
│   │   │   │   │       │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       │   ├── opentelemetry-datadog v0.8.0 (*)
│   │   │   │   │       │   ├── opentelemetry-jaeger v0.19.0
│   │   │   │   │       │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       │   ├── opentelemetry-otlp v0.13.0 (*)
│   │   │   │   │       │   └── opentelemetry-zipkin v0.18.0
│   │   │   │   │       │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │       ├── opentelemetry-jaeger v0.19.0 (*)
│   │   │   │   │       ├── opentelemetry-otlp v0.13.0 (*)
│   │   │   │   │       └── opentelemetry-zipkin v0.18.0 (*)
│   │   │   │   │       [dev-dependencies]
│   │   │   │   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── hyper-timeout v0.4.1
│   │   │   │   │   └── tonic v0.9.2 (*)
│   │   │   │   ├── hyperlocal v0.8.0
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   [dev-dependencies]
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── reqwest v0.11.24 (*)
│   │   │   │   ├── tonic v0.9.2 (*)
│   │   │   │   └── wiremock v0.5.22
│   │   │   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │       [dev-dependencies]
│   │   │   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── reqwest v0.11.24 (*)
│   │   │   └── tonic v0.9.2 (*)
│   │   ├── petgraph v0.6.4
│   │   │   ├── apollo-federation v0.0.8 (*)
│   │   │   └── daggy v0.8.0
│   │   │       └── test-span v0.7.0
│   │   │           [dev-dependencies]
│   │   │           └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   ├── serde_json v1.0.114
│   │   │   ├── access-json v0.1.0
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── apollo-federation v0.0.8 (*)
│   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── assert-json-diff v2.0.2
│   │   │   │   └── wiremock v0.5.22 (*)
│   │   │   ├── axum v0.6.20 (*)
│   │   │   ├── deno_core v0.200.0
│   │   │   │   ├── deno_console v0.115.0
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1
│   │   │   │   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   [build-dependencies]
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   ├── deno_crypto v0.129.0
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   │   [build-dependencies]
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   ├── deno_url v0.115.0
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   │   [build-dependencies]
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   ├── deno_web v0.146.0
│   │   │   │   │   ├── deno_crypto v0.129.0 (*)
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   │   [build-dependencies]
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   ├── deno_webidl v0.115.0
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   │   [build-dependencies]
│   │   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   │   [build-dependencies]
│   │   │   │   └── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   ├── graphql_client v0.13.0
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── http-types v2.12.0
│   │   │   │   └── wiremock v0.5.22 (*)
│   │   │   ├── jsonpath-rust v0.3.5
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── jsonpath_lib v0.3.0
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── jsonschema v0.17.1
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── jsonwebtoken v9.2.0
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── opentelemetry-stdout v0.1.0
│   │   │   │   [dev-dependencies]
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── opentelemetry-zipkin v0.18.0 (*)
│   │   │   ├── opentelemetry_sdk v0.20.0
│   │   │   │   ├── opentelemetry v0.20.0
│   │   │   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   ├── opentelemetry-datadog v0.8.0 (*)
│   │   │   │   │   ├── opentelemetry-jaeger v0.19.0 (*)
│   │   │   │   │   ├── opentelemetry-semantic-conventions v0.12.0
│   │   │   │   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   │   ├── opentelemetry-datadog v0.8.0 (*)
│   │   │   │   │   │   ├── opentelemetry-jaeger v0.19.0 (*)
│   │   │   │   │   │   ├── opentelemetry-otlp v0.13.0 (*)
│   │   │   │   │   │   └── opentelemetry-zipkin v0.18.0 (*)
│   │   │   │   │   ├── opentelemetry-zipkin v0.18.0 (*)
│   │   │   │   │   └── tracing-opentelemetry v0.21.0
│   │   │   │   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   │   [dev-dependencies]
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── opentelemetry-otlp v0.13.0 (*)
│   │   │   │   ├── opentelemetry-prometheus v0.13.0
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── opentelemetry-proto v0.3.0 (*)
│   │   │   │   ├── opentelemetry-stdout v0.1.0 (*)
│   │   │   │   └── tracing-opentelemetry v0.21.0 (*)
│   │   │   ├── proteus v0.5.0
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── reqwest v0.11.24 (*)
│   │   │   ├── router-bridge v0.5.16+v2.7.1 (*)
│   │   │   ├── schemars v0.8.16
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── serde_json_bytes v0.2.2
│   │   │   │   ├── apollo-compiler v1.0.0-beta.13 (*)
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   ├── sourcemap v6.4.1
│   │   │   │   └── deno_core v0.200.0 (*)
│   │   │   ├── test-span v0.7.0 (*)
│   │   │   ├── tracing-subscriber v0.3.18
│   │   │   │   ├── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── test-log v0.2.14
│   │   │   │   │   [dev-dependencies]
│   │   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   ├── test-span v0.7.0 (*)
│   │   │   │   ├── tracing-opentelemetry v0.21.0 (*)
│   │   │   │   └── tracing-test v0.2.4
│   │   │   │       [dev-dependencies]
│   │   │   │       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   │   [dev-dependencies]
│   │   │   │   └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
│   │   │   └── wiremock v0.5.22 (*)
│   │   └── serde_json_bytes v0.2.2 (*)
│   └── lru v0.12.2
│       └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
├── jsonschema v0.17.1 (*)
└── rhai v1.17.1
    └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)
    [dev-dependencies]
    └── apollo-router v1.43.0 (/Users/nickmarsh/src/router/apollo-router)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bonnici It looks like it will work with just updating the deps here:

cargo update -p ahash
cargo update -p curve25519-dalek@4.0.0

(somehow that other dependency has a similar issue)

Copy link
Contributor Author

@bonnici bonnici Apr 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Geal Thank you for that but unfortunately I ran into yet another strange issue I have no idea how to fix. The cargo update -p commands got me past the unknown feature stdsimd error but now I'm getting an even stranger linker error:

error: linking with `cc` failed: exit status: 1
  |
  = note: env -u IPHONEOS_DEPLOYMENT_TARGET -u TVOS_DEPLOYMENT_TARGET LC_ALL="C" PATH="/Users/nickmarsh/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/bin:/opt/homebrew/opt/curl/bin:/Users/nickmarsh/google-cloud-sdk/bin:/Users/nickmarsh/.volta/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Users/nickmarsh/.cargo/bin:/Users/nickmarsh/.rover/bin:/Users/nickmarsh/Library/Application Support/JetBrains/Toolbox/scripts" VSLANG="1033" ZERO_AR_DATE="1" "cc" "-arch" "arm64" "/var/folders/q2/y4vh72_9197819gxrzgwtx3r0000gn/T/rustcQOdT9N/symbols.o" "-Wl,-rpath" "-Xlinker" "/Users/nickmarsh/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib" "-lrustc-nightly_rt.asan" "/Users/nickmarsh/src/router/target/aarch64-apple-darwin/release/deps/apollo_router_studio_interop-38c9c488e24b25f8.apollo_router_studio_interop.a0f57017173ec7f8-cgu.0.rcgu.o" "/Users/nickmarsh/src/router/target/aarch64-apple-darwin/release/deps/apollo_router_studio_interop-38c9c488e24b25f8.1euljvum1py0sn1w.rcgu.o" "-L" 

< huge list of folders goes here >

"-lc++" "-framework" "SystemConfiguration" "-framework" "Security" "-framework" "CoreFoundation" "-framework" "Security" "-liconv" "-lSystem" "-lc" "-lm" "-L" "/Users/nickmarsh/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib" "-o" "/Users/nickmarsh/src/router/target/aarch64-apple-darwin/release/deps/apollo_router_studio_interop-38c9c488e24b25f8" "-nodefaultlibs"
  = note: ld: warning: search path '/Users/nickmarsh/src/router/target/aarch64-apple-darwin/release/build/libz-ng-sys-2ace1440088f968b/out/lib64' not found
          ld: initializer pointer has no target in '/Users/nickmarsh/src/router/target/aarch64-apple-darwin/release/deps/libproteus-6844fdb36340bdae.rlib[3](proteus-6844fdb36340bdae.proteus.9e4a919a603b00d1-cgu.0.rcgu.o)'
          clang: error: linker command failed with exit code 1 (use -v to see invocation)


error: could not compile `router-fuzz` (bin "apollo_router_studio_interop") due to 1 previous error
Error: failed to build fuzz script: ASAN_OPTIONS="detect_odr_violation=0" RUSTFLAGS="-Cpasses=sancov-module -Cllvm-args=-sanitizer-coverage-level=4 -Cllvm-args=-sanitizer-coverage-inline-8bit-counters -Cllvm-args=-sanitizer-coverage-pc-table -Cllvm-args=-sanitizer-coverage-trace-compares --cfg fuzzing -Clink-dead-code -Zsanitizer=address -Cdebug-assertions -C codegen-units=1" "cargo" "build" "--manifest-path" "/Users/nickmarsh/src/router/fuzz/Cargo.toml" "--target" "aarch64-apple-darwin" "--release" "--config" "profile.release.debug=true" "--bin" "apollo_router_studio_interop"

The fuzz build also started taking ages to finish (15+ minutes) and using up most of my free memory. Any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like the fuzzing framework is trying to do too much, while the router's code is too big. So we need to change gears. I left suggestions in the PR that will make it build and run quickly, I just tested. The nice thing with that solution is that we won't need to reexport the module.
You also need to remove this line:

mod invariant_router;

Meanwhile I have a PR up to build the fuzzers in CI and make sure we don't regress there #4925

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I had to make a few other changes but it looks like it's all working now.

@SimonSapin
Copy link
Contributor

apollo_router__configuration__tests__schema_generation.snap.new should not be committed to the repository. Instead please run cargo install cargo-insta (once) and cargo insta review (after a snapshot test failures) to review the change to expected output of a snapshot test. In the case of the "configuration schema generation" test, a change is expected when adding a new config key.

Comment on lines 112 to 114
// For fuzz testing
pub use crate::apollo_studio_interop::generate_usage_reporting;
pub use crate::apollo_studio_interop::UsageReportingComparisonResult;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// For fuzz testing
pub use crate::apollo_studio_interop::generate_usage_reporting;
pub use crate::apollo_studio_interop::UsageReportingComparisonResult;

fuzz/Cargo.toml Outdated
apollo-smith = { version = "0.5.0", features = ["parser-impl"] }
apollo-parser = "0.7.6"
apollo-router = { path = "../apollo-router" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
apollo-router = { path = "../apollo-router" }

Comment on lines 12 to 13
use apollo_router::_private::generate_usage_reporting;
use apollo_router::_private::UsageReportingComparisonResult;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use apollo_router::_private::generate_usage_reporting;
use apollo_router::_private::UsageReportingComparisonResult;
#[path = "../../apollo-router/src/apollo_studio_interop/mod.rs"]
mod apollo_router_usage_reporting;
use apollo_router_usage_reporting::generate_usage_reporting;
use apollo_router_usage_reporting::UsageReportingComparisonResult;

UsageReportingComparisonResult::StatsReportKeyNotEqual
| UsageReportingComparisonResult::BothNotEqual
) {
tracing::warn!(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are the 3 metrics calls (here and at lines 613 and 630) at different log levels?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used info for the "happy state" and warn for the "unhappy state". Should I be using warn for all the metric traces?

@@ -447,6 +447,7 @@ where
});
}

// This will be overridden when running in ApolloMetricsGenerationMode::New mode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will be able to do even better: since usage reporting only depends on the query and the schema, we can calculate it way earlier, in the query analysis layer, and then we can apply some query normalization before calling into query planning, which will reduce the number of generated query plans. Example: the same query but with a different operation name will point to the same stored plan

.experimental_apollo_metrics_generation_mode,
ApolloMetricsGenerationMode::New | ApolloMetricsGenerationMode::Both
) {
// If the query is filtered, we want to generate the signature using the original query and generate the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to generate the signature from the original query, but do we want to generate the usage reporting from the original too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code above:

// the `statsReportKey` field should match the original query instead of the filtered query, to index them all under the same query

We only regenerate the query, not the referenced fields. I wanted to keep the behaviour of the new process the same as the old process so we can do an equal comparison. But I think ideally we would probably want to just use the original query for both, since that's the operation that was executed and the fields that were referenced. But I thought there might be a reason why the signature was regenerated so didn't want to change that.

}

#[cfg(test)]
mod tests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could you split the tests in a separate file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried a few ways of doing this but the tests wouldn't run in any attempt I made, can you see what I've done wrong in the latest commit?

Comment on lines 76 to 83
let mut sorted_self_field_names = self_refs.field_names.clone();
sorted_self_field_names.sort();
let mut sorted_other_field_names = other_refs.field_names.clone();
sorted_other_field_names.sort();

if sorted_self_field_names != sorted_other_field_names {
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there's a lot of fields, it might be faster to collect the names in a HashSet and then check that they are equal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I think I did it this way because originally I had it so the order mattered. I'll update this.

sorted_fragments.sort_by_key(|&(k, _)| k);

sorted_fragments.into_iter().for_each(|(_, f)| {
result.push_str(&ApolloReportingSignatureFormatter::Fragment(f).to_string())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
result.push_str(&ApolloReportingSignatureFormatter::Fragment(f).to_string())
write!(&mut result, "{}", ApolloReportingSignatureFormatter::Fragment(f));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that results in less allocations overall

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one didn't work for me - I got the error cannot write into &mut std::string::String

}
}

fn extract_fields(&mut self, parent_type: &String, selection_set: &SelectionSet) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn extract_fields(&mut self, parent_type: &String, selection_set: &SelectionSet) {
fn extract_fields(&mut self, parent_type: &str, selection_set: &SelectionSet) {

The String is forcing you to convert first into an allocated String everywhere, then refer to it by a reference, while the underlying type could directly defer to a &str

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this and other perf stuff could be adressed in a follow up, that's not blocking)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to do an .into() a few times after making this change because other functions were expecting a String so I don't know if I actually made it any better or not.

@garypen garypen mentioned this pull request Apr 10, 2024
6 tasks
@Geal
Copy link
Contributor

Geal commented Apr 12, 2024

the test_updated CI failure will be fixed once #4945 is merged

@Geal Geal enabled auto-merge (squash) April 12, 2024 08:35
@Geal Geal merged commit 847d055 into apollographql:dev Apr 12, 2024
12 of 13 checks passed
@abernix abernix mentioned this pull request Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants