Repository navigation
fix: count resyncs from Flow events so the starter no longer needs spring-web (#415) (CP: 5.0) - #449
Merged
Merged
Conversation
…ring-web (#415) (CP: 5.0) ## Summary The `vaadin.resync` metric is now counted from events that Flow fires, not by a servlet filter that reads UIDL request bodies. The starter no longer needs spring-web or the servlet API, so it compiles again against Flow 25.4. Resyncs over push are now counted too, and a new `out_of_sync` type is added. ## What changed **Breaking:** Several public classes are removed: `ResyncDetectionFilter`, `ResyncDetector` and `ResyncInspector` (micrometer module), and `SpringResyncDetectionFilter` (spring module). The starter no longer registers the resync `FilterRegistrationBean`. This only affects apps that used these classes directly or overrode that bean. Everyone else gets the same metric without doing anything. **Behavior change:** `vaadin.resync` now also counts events on push requests. It has a new tag value `type=out_of_sync` for messages with an id the server did not expect (the user sees the session synchronization error). Dashboards or alerts that expect only `resend` and `resync` may see new data. - New package-private `ResyncMetricsBinder` listens for `ClientMessageResentEvent`, `UIResynchronizationEvent` and `MessageIdSyncErrorEvent` on the service event bus. `MetricsServiceInitListener` registers it when `vaadin.observability.resync` is on (the default). It registers the three counters up front, so each `type` reports 0 before its first event. - Removed the `spring-web` and `jakarta.servlet-api` dependencies from the starter. Since spring-web may now be missing at runtime, `SpringMetricsServiceInitListener` checks for it before enriching the Spring HTTP observation. Without it there is no HTTP observation to enrich, and using the enricher would throw `NoClassDefFoundError` on the first request. - Fixed `MetricsCollectorElement`: a UI resync detaches and re-attaches every node in place. The element's detach listener then added it to the UI again, which caused an endless loop, so the resync request never finished. Now it only re-adds itself when it is no longer attached. That also covers a collector inside a layout that gets removed from the UI. - Updated the README metric and setting descriptions and the architecture diagram. ## API Changes 5 classes affected: 4 removed, 1 constant added ### com.vaadin.observability.micrometer.MeterNames ```java // Added public static final String RESYNC_TYPE_OUT_OF_SYNC = "out_of_sync" // message id the server did not expect ``` ### com.vaadin.observability.micrometer.ResyncDetectionFilter ```java // Removed public final class ResyncDetectionFilter implements Filter public ResyncDetectionFilter(MeterRegistry registry) public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) ``` ### com.vaadin.observability.micrometer.ResyncDetector ```java // Removed public final class ResyncDetector public static final int NO_CLIENT_ID = -1 public enum Kind { NORMAL, RESEND, RESYNC } public record Result(Kind kind, int lastClientId) public ResyncDetector(MeterRegistry registry) public Result inspect(String requestBody, int previousClientId) ``` ### com.vaadin.observability.micrometer.ResyncInspector ```java // Removed public final class ResyncInspector public ResyncInspector(MeterRegistry registry) public static boolean isUidl(HttpServletRequest request) public static String uiId(HttpServletRequest request) public void inspect(String body, HttpSession session, String uiId, Object mutex) ``` ### com.vaadin.observability.spring.SpringResyncDetectionFilter ```java // Removed public final class SpringResyncDetectionFilter extends OncePerRequestFilter public SpringResyncDetectionFilter(MeterRegistry registry) protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) ``` ## Test summary **Resync metrics binder:** - Every type reports 0 before its first event - Counts resend, resync and out-of-sync events under their own type - Stops counting after the registration is removed - Registered only when the resync setting is on **Metrics collector element:** - Added back to its UI after being removed, directly or with an enclosing layout - Not added again after a UI resynchronization **Spring listener:** - Updates the Spring HTTP observation when spring-web is on the classpath - HTTP observation enrichment is skipped, without errors, when spring-web is not on the classpath **Starter (end-to-end):** - Resend, out-of-sync and resync exported to Prometheus as `vaadin_resync_total` - Not covered: counting over push requests --------- Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Artur Signell <artur@vaadin.com>SpringResyncDetectionFilter.java
Member
|
This removes public classes ( |
Member
|
Can those classes be used by users for something? |
Collaborator
Author
|
434 is not needed after this one. They were needed for manual setup in plain spring and standalone settings, but after this they have no use. |
heruan
approved these changes
Oct 7, 2026
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.
Summary
The
vaadin.resyncmetric is now counted from events that Flow fires, not by a servlet filter that reads UIDL request bodies. The starter no longer needs spring-web or the servlet API, so it compiles again against Flow 25.4. Resyncs over push are now counted too, and a newout_of_synctype is added.What changed
Breaking: Several public classes are removed:
ResyncDetectionFilter,ResyncDetectorandResyncInspector(micrometer module), andSpringResyncDetectionFilter(spring module). The starter no longer registers the resyncFilterRegistrationBean. This only affects apps that used these classes directly or overrode that bean. Everyone else gets the same metric without doing anything.Behavior change:
vaadin.resyncnow also counts events on push requests. It has a new tag valuetype=out_of_syncfor messages with an id the server did not expect (the user sees the session synchronization error). Dashboards or alerts that expect onlyresendandresyncmay see new data.ResyncMetricsBinderlistens forClientMessageResentEvent,UIResynchronizationEventandMessageIdSyncErrorEventon the service event bus.MetricsServiceInitListenerregisters it whenvaadin.observability.resyncis on (the default). It registers the three counters up front, so eachtypereports 0 before its first event.spring-webandjakarta.servlet-apidependencies from the starter. Since spring-web may now be missing at runtime,SpringMetricsServiceInitListenerchecks for it before enriching the Spring HTTP observation. Without it there is no HTTP observation to enrich, and using the enricher would throwNoClassDefFoundErroron the first request.MetricsCollectorElement: a UI resync detaches and re-attaches every node in place. The element's detach listener then added it to the UI again, which caused an endless loop, so the resync request never finished. Now it only re-adds itself when it is no longer attached. That also covers a collector inside a layout that gets removed from the UI.API Changes
5 classes affected: 4 removed, 1 constant added
com.vaadin.observability.micrometer.MeterNames
com.vaadin.observability.micrometer.ResyncDetectionFilter
com.vaadin.observability.micrometer.ResyncDetector
com.vaadin.observability.micrometer.ResyncInspector
com.vaadin.observability.spring.SpringResyncDetectionFilter
Test summary
Resync metrics binder:
Metrics collector element:
Spring listener:
Starter (end-to-end):
vaadin_resync_totalSpringResyncDetectionFilter.java
Description
Please list all relevant dependencies in this section and provide summary of the change, motivation and context.
Fixes # (issue)
Type of change
Checklist
Additional for
Featuretype of change