Expire brokered credentials, filter by release, and fix the granule b… - #55
Merged
Merged
Conversation
…lock size
Four fixes from a review of the MAAP/S3 path against the platform docs.
P1, credential expiry. get_s3fs() cached a session for the life of the
process, but MAAP-brokered DAAC credentials expire -- measured against the live
broker, the NSIDC response carries expiration exactly one hour out. A read
phase that outlives it starts 403-ing partway through, which at a per-tile
fan-out reads as a random data error rather than as an expiry. The cache now
holds (filesystem, expires_at) and re-derives inside a 600 s margin. An
unparseable or absent expiration falls back to a SHORT lifetime rather than an
unlimited one: guessing "no expiry" from a value we failed to read is how a
session outlives its credentials. Sessions with nothing to expire -- daac=None,
which uses the self-refreshing default chain -- cache as before.
Exercised against the live broker: expiry parsed, repeat call cached, a session
forced inside the margin re-derived, daac=None recorded no expiry, a malformed
expiration warned and fell back to 40 minutes, and a real granule still read.
C6, release filtering. find_ATL11_granules() searched with no filter at all, so
it returned every generation CMR holds for the short name. That is benign only
while exactly one per-granule index subtree is staged -- a second would make
every tile read both and double-count its data, silently. granule_release= now
restricts results to one (cycles, release, version) triple, matched on granule
names because CMR's own version filter selects the COLLECTION version (007) and
cannot separate cycle ranges or granule versions within it.
release_spec() parses '007_cycle_03_31_v04' into ('0331','007','04'). IT IS
DELIBERATELY PER-PRODUCT, WITH NO MODULE-LEVEL DEFAULT: ATL11 and ATL11XO are
normally different generations -- rel_006_0331 pairs --ATL11_release=
007_cycle_03_31_v04 with --ATL11xo_version=007_cycle_03_30_v03, differing in
both cycle range and version under one release -- so a single global "current
release" would silently filter a crossover search by ATL11's cycles. Verified
both parse distinctly and that a granule of either generation matches only its
own spec.
C7, missing indices. A granule whose index was absent warned and was skipped,
which silently produced a partial fit: a half-uploaded index tree (~8100 files)
gave a tile fewer granules than it should have had, with nothing recorded. Now
that the search is filtered to the generation we indexed, every granule that
reaches the read is one we expect an index for, so its absence is a fault and
raises. missing_index='skip' restores best-effort reads, and the option is
threaded through all three entry points.
C5, block size. geoIndex.get_data() opened the granule with no block_size, so
DEFAULT_REMOTE_BLOCK_SIZE never reached the read it was measured for --
scattered index_ranges out of a chunked, compressed granule, where Q27 measured
35 MiB against 6.6 MiB for the same window. The index-file read is left on the
larger default deliberately: an index averages ~250 KiB and is read end to end.
Also: the hard-coded earthaccess.login(strategy='netrc') had a THIRD site,
tilingSchema.resolve_files_for_box() (the crossover path), which the review
missed and a grep found. The helper now lives in io_utils as
try_earthaccess_login(), beside get_s3fs(), so the login policy and the
credential policy stay together; query_ATL11_cloud keeps the old private name
as a delegating alias for outside callers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013MdMEXw2s6eeGtaGcaDxpF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…lock size
Four fixes from a review of the MAAP/S3 path against the platform docs.
P1, credential expiry. get_s3fs() cached a session for the life of the process, but MAAP-brokered DAAC credentials expire -- measured against the live broker, the NSIDC response carries expiration exactly one hour out. A read phase that outlives it starts 403-ing partway through, which at a per-tile fan-out reads as a random data error rather than as an expiry. The cache now holds (filesystem, expires_at) and re-derives inside a 600 s margin. An unparseable or absent expiration falls back to a SHORT lifetime rather than an unlimited one: guessing "no expiry" from a value we failed to read is how a session outlives its credentials. Sessions with nothing to expire -- daac=None, which uses the self-refreshing default chain -- cache as before.
Exercised against the live broker: expiry parsed, repeat call cached, a session forced inside the margin re-derived, daac=None recorded no expiry, a malformed expiration warned and fell back to 40 minutes, and a real granule still read.
C6, release filtering. find_ATL11_granules() searched with no filter at all, so it returned every generation CMR holds for the short name. That is benign only while exactly one per-granule index subtree is staged -- a second would make every tile read both and double-count its data, silently. granule_release= now restricts results to one (cycles, release, version) triple, matched on granule names because CMR's own version filter selects the COLLECTION version (007) and cannot separate cycle ranges or granule versions within it.
release_spec() parses '007_cycle_03_31_v04' into ('0331','007','04'). IT IS DELIBERATELY PER-PRODUCT, WITH NO MODULE-LEVEL DEFAULT: ATL11 and ATL11XO are normally different generations -- rel_006_0331 pairs --ATL11_release= 007_cycle_03_31_v04 with --ATL11xo_version=007_cycle_03_30_v03, differing in both cycle range and version under one release -- so a single global "current release" would silently filter a crossover search by ATL11's cycles. Verified both parse distinctly and that a granule of either generation matches only its own spec.
C7, missing indices. A granule whose index was absent warned and was skipped, which silently produced a partial fit: a half-uploaded index tree (~8100 files) gave a tile fewer granules than it should have had, with nothing recorded. Now that the search is filtered to the generation we indexed, every granule that reaches the read is one we expect an index for, so its absence is a fault and raises. missing_index='skip' restores best-effort reads, and the option is threaded through all three entry points.
C5, block size. geoIndex.get_data() opened the granule with no block_size, so DEFAULT_REMOTE_BLOCK_SIZE never reached the read it was measured for -- scattered index_ranges out of a chunked, compressed granule, where Q27 measured 35 MiB against 6.6 MiB for the same window. The index-file read is left on the larger default deliberately: an index averages ~250 KiB and is read end to end.
Also: the hard-coded earthaccess.login(strategy='netrc') had a THIRD site, tilingSchema.resolve_files_for_box() (the crossover path), which the review missed and a grep found. The helper now lives in io_utils as try_earthaccess_login(), beside get_s3fs(), so the login policy and the credential policy stay together; query_ATL11_cloud keeps the old private name as a delegating alias for outside callers.
Claude-Session: https://claude.ai/code/session_013MdMEXw2s6eeGtaGcaDxpF