Skip to content

Read the console's sampling settings on HarmonyOS - #33

Open
Fiona2016 wants to merge 5 commits into
mainfrom
feat/rum-remote-config
Open

Read the console's sampling settings on HarmonyOS#33
Fiona2016 wants to merge 5 commits into
mainfrom
feat/rum-remote-config

Conversation

@Fiona2016

Copy link
Copy Markdown
Collaborator

RUM on HarmonyOS collected at whatever rate the application was built with. Moving that rate meant shipping a release and waiting for it to roll out, while the other platforms could already turn the knob from the console. This adds the same remote configuration path here.

How it behaves

Settings are read from the RUM configuration endpoint at the rhythm of the sessions that consume them: once at start-up, once whenever a new session begins, and on return to the foreground when the console asks for it. What arrives is stored, so the first session of the next launch is already drawn under it.

A published rate applies to the next session drawn; a session already under way is never re-decided. View documents now report the rate the session was actually drawn with, plus the settings version, so extrapolation and audits line up with the draw that kept the session rather than with the values passed to init.

Nothing in this path can hold up initialisation or interrupt collection. A request that fails, times out or comes back unreadable leaves the stored values exactly as they were — wiping them on a bad minute would swing a whole fleet back to the values it was built with, which is the opposite of what someone who moved a knob deliberately wants. Retries are two per outage, spread by a jitter, then nothing until the next natural trigger.

Application-facing API

FlashcatRum.enable(new RumConfigurationBuilder(applicationId)
  .setSessionSampleRate(100)
  .setRemoteConfigurationEnabled(true)          // off by default
  .setBeforeSampling((context: BeforeSamplingContext): number | undefined => {
    // the last word on the rate: return one to override, or nothing to accept it
    return isBeingDebugged(context.custom) ? 100 : undefined;
  })
  .build());

GlobalRumMonitor.get().setForcedSession();      // keep this visitor whatever the fleet is on
GlobalRumMonitor.get().getRemoteConfig();       // the console's custom values, decoded

A hook that throws or returns a rate outside 0..100 is ignored: a mistake in the host application must not take collection down with it. setForcedSession() keeps a session the rate would have dropped, and does nothing while a forced session is already running.

Notes for reviewers

  • Feature modules receive no HarmonyOS Context, so the credentials and the small amount of storage this needs come from the core, which already owns both: SdkCore gains an intake accessor and a two-method settings store.
  • The layout mirrors the Android SDK (RemoteConfigStore / RemoteConfigController), with one deliberate difference: the drawn-configuration snapshot is held in memory rather than persisted, because nothing on this platform reads it back across launches.
  • 23 unit tests cover the parsing, storage, retry, draw, hook and forced-session rules, including the failure paths that must leave stored values untouched. The demo application gains a scenario that drives the whole path from the command line.

RUM on HarmonyOS collected at whatever rate the app was built with: moving
that rate meant shipping a release and waiting for it to roll out, while the
other platforms could already turn the knob from the console.

The settings are read from the same endpoint the other SDKs use, at the rhythm
of the sessions that consume them: once at start-up, once per new session, and
on return to the foreground when the console asks for it. What arrives is
stored, so the first session of a launch is already drawn under it. Nothing
here can hold up initialisation or interrupt collection — a request that fails,
times out or comes back unreadable leaves the stored values exactly as they
were, because wiping them on a bad minute would swing a fleet back to the
values it was built with, the opposite of what someone who moved a knob wants.

A published rate applies to the NEXT session drawn; a session already under way
is never re-decided. View documents now report the rate the session was
actually drawn with plus the settings version, so extrapolation and audits line
up with the draw that kept the session rather than with the init values.

Two application-facing controls come with it:

- setForcedSession() keeps a visitor the rate would have dropped — the support
  case where someone needs this one user's sessions whatever the fleet is on.
- beforeSampling() has the last word on the rate, called synchronously at each
  draw with the rate that would apply and the console's custom values. A throw
  or an out-of-range answer is ignored: a mistake in the host application must
  not take collection down with it.

Feature modules get no HarmonyOS Context of their own, so the credentials and
the small amount of storage this needs come from the core, which already owns
both. The demo app gains a scenario that drives the whole path from the command
line.
Three things the first pass left behind: `stopSession`'s documentation ended up
attached to a method inserted above it, two error-to-string helpers with one
caller each where every other call site in this codebase writes the expression
inline, and the same JSON-object parse in both the store and the controller —
the store's is now shared, since the endpoint's body and the store's own
entries need exactly the same tolerance.
…ot read

The server states the shape of the body it wrote in `schema_version`. A
reader that guesses instead of checking is exactly what that field
exists to prevent: a payload shaped for a newer reader can be misread
field by field while every individual field still parses, and
half-understood sampling settings are worse than none.

The check has to be honoured by the first SDK that ships. Refusing can
only be done by code already on the device, so a version added later
would be ignored by exactly the clients it needs to protect.

`apply()` now reports one of three outcomes instead of a boolean:

  APPLIED             the body was read and its values are stored
  UNREADABLE          not a configuration at all - ask again
  UNSUPPORTED_SCHEMA  a contract this SDK does not read - refused whole

Only UNREADABLE is retried. A schema we do not know is an answer, not a
failure: asking again would fetch the same refusal, so a server-side
schema bump cannot turn a fleet into a retry storm. Nothing from a
refused body reaches storage, not even the fields that happened to
parse.
A response with no schema stamp at all was refused as a shape this SDK cannot
read. A body without one is, by construction, the shape that existed before the
stamp did — which is the shape this reader was written against. Refusing it
switches remote configuration silently off against a server that merely
predates the field, and nothing says so: the refusal path is the same one a
body we genuinely cannot read takes, so there is no error to notice.

Only a stamp that is present and unrecognised is a refusal now, which is what
the web SDK already did. The two no longer disagree about the same response.
forceSession() returned early when the session was already forced and being
collected, then set the flag and returned again on the same "already being
collected" condition. Reaching the first guard meant the flag was already set,
so the only thing it did was skip setting it to the value it already had.
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.

1 participant