Skip to content

O3-5770: Report queue entry metrics per queue, and for open waits - #123

Open
UjjawalPrabhat wants to merge 4 commits into
openmrs:mainfrom
UjjawalPrabhat:O3-5770-per-queue-metrics
Open

O3-5770: Report queue entry metrics per queue, and for open waits#123
UjjawalPrabhat wants to merge 4 commits into
openmrs:mainfrom
UjjawalPrabhat:O3-5770-per-queue-metrics

Conversation

@UjjawalPrabhat

@UjjawalPrabhat UjjawalPrabhat commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds groupBy=queue plus three open-wait metrics to /queue-entry-metric, so a client can get a per-queue breakdown in one request instead of pulling every unfinished entry and counting them in the browser. Raised from
#2681.

Existing callers are unaffected: count and averageWaitTime are still returned when no metric is named, the new ones only when asked for.

Worth noting:

  • longestOpenWait.queueEntry uses a custom representation rather than REF, which for a queue entry drags six lazy associations along for every queue reported on. The cost is that the rep string is not covered by a test, the controller test mocks ConversionUtil wholesale and the module has no web-context-sensitive test setup.
  • The queues array is seeded from the queue search but extended from the entries, because the two do not select identically: the queue search excludes retired queues, the entry search has no such filter. Without that the totals could exceed the sum of the rows.

Related Issue

O3-5770

@UjjawalPrabhat
UjjawalPrabhat force-pushed the O3-5770-per-queue-metrics branch from 1bfe65d to 963e047 Compare August 30, 2026 20:20
UjjawalPrabhat added a commit to UjjawalPrabhat/openmrs-esm-patient-management that referenced this pull request Aug 30, 2026
Rolls the clinic metrics up server-side via groupBy=queue, rather than fetching
every unfinished queue entry at a location and reducing them in the browser.
Requires openmrs/openmrs-module-queue#123; reverting this commit drops that
dependency.
Comment thread api/src/main/java/org/openmrs/module/queue/utils/QueueUtils.java Outdated
- Floor an open wait at zero, so a startedAt in the future reports as not
  yet waiting rather than as a negative duration
- Report the queue under a custom representation: REF carries neither the
  location and service that label a row nor the retired flag, and DEFAULT
  also carries the allowed priorities and statuses
- Sort the queue rows by name, so repeating a request returns them in the
  same order
- Cover the branch that reports only the queues the request named, and the
  one where an unrecognised groupBy value keeps the flat response
An entry's startedAt is reset when it is called in to be seen, so a
client asking for the open wait metrics with only isEnded=false has In
Service entries measured on their time in service rather than on how
long they waited.

Adds a waitStatus parameter naming the statuses that count as waiting;
averageOpenWaitTime and longestOpenWait are then computed over only
those entries. count, averageWaitTime and countsByStatus keep the full
list, and a request without the parameter behaves as before.

@NethmiRodrigo NethmiRodrigo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Some minor things

The wrapper resolves a blank queue ref to a null element, which would then
reach the sort by name and fail there.

Also covers the per-queue rows in the waitStatus test, and that the location
and service filters reach the queue search.
@sonarqubecloud

sonarqubecloud Bot commented Sep 3, 2026

Copy link
Copy Markdown

@NethmiRodrigo NethmiRodrigo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks @UjjawalPrabhat! One small follow-on from the blank ref fix, and a nit.

// One instant for every duration, so the per-queue figures and the totals cannot disagree
Date asOf = new Date();
String[] waitStatusArray = parameters.get(WAIT_STATUS);
List<Concept> waitStatuses = (waitStatusArray == null ? null : services.getConcepts(waitStatusArray));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same for a blank waitStatus ref, otherwise filterByStatus measures over no entries and both open wait metrics come back null.

Suggested change
List<Concept> waitStatuses = (waitStatusArray == null ? null : services.getConcepts(waitStatusArray));
List<Concept> waitStatuses = null;
if (waitStatusArray != null) {
waitStatuses = services.getConcepts(waitStatusArray);
// A blank status ref resolves to a null element
waitStatuses.removeIf(c -> c == null);
}

Lets also add a test for waitStatus="" that asserts the wait metrics match the unfiltered values.


List<SimpleObject> queues = (List<SimpleObject>) result.get(QUEUES);
assertThat(queues, hasSize(1));
assertThat(((Queue) queues.get(0).get(QUEUE)).getName(), equalTo("Triage"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: lets also assert that the entry landed on the surviving row

Suggested change
assertThat(((Queue) queues.get(0).get(QUEUE)).getName(), equalTo("Triage"));
assertThat(((Queue) queues.get(0).get(QUEUE)).getName(), equalTo("Triage"));
assertThat(queues.get(0).get(COUNT), equalTo(1));

@NethmiRodrigo NethmiRodrigo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM, aside from the above few nits! Thanks @UjjawalPrabhat!

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.

2 participants