allthingssecurity opened a new pull request, #27674: URL: https://github.com/apache/camel/pull/27674
# Description [CAMEL-25523](https://issues.apache.org/jira/browse/CAMEL-25523) `SlackConsumer.poll()` made one `conversations.history` request with `oldest` (the timestamp of the last consumed message) and `limit` = `maxResults` (default 10), routed the messages of that response and moved the timestamp to the most recent of them. Slack returns the most recent messages of the range first, at most `limit` of them, and signals the older ones with `has_more` and `response_metadata.next_cursor`, which the consumer ignored. So when more than `maxResults` messages were posted between two polls (default delay 10 seconds), the older ones were skipped without a trace; with the docs example `maxResults=1`, two messages within one poll interval lost one. Now a poll that follows the first one reads the following pages with `next_cursor` (same `limit`) when the response has `has_more`, and routes all the new messages in the same order as before (most recent first, or oldest first with `naturalOrder`). A poll with at most `maxResults` new messages sends the same single request as before, and the first poll (which reads the last message of the history) is unchanged. A poll can now route more than `maxResults` messages, so the option description (with the generated `slack.json`, the catalog and the endpoint DSL copies), the component docs (with the catalog copy) and the 4.23 upgrade guide say that `maxResults` is the number of messages per request, and to raise it for a busy channel. If the request for a following page fails, for example because Slack rate limits it (apps that Slack limits to one `conversations.history` request per minute, commercially distributed apps outside the Slack Marketplace since May 2025, get HTTP 429 for the second page), the poll does not fail: the consumer routes the most recent messages it has already read and moves the timestamp, as main does, and logs a WARN with the error saying that the older messages of that poll were skipped. So such apps are never worse off than with main, and a failing following page does not make every poll fail. The messages of a poll are held in memory until they are routed. The component docs (with the catalog copy) and the upgrade note describe this fallback. Tests: - New `SlackConsumerHasMoreTest`: a local HTTP server (via the `serverUrl` option) answers `conversations.list` and `conversations.history` as Slack does (`oldest` exclusive, most recent first, `limit` per page, `has_more`, `next_cursor`); with `maxResults=2`, five messages are posted at once after the first poll, in the default order and with `naturalOrder=true`. - A third test answers every following-page request with HTTP 429 (`Retry-After: 60`, `{"ok":false,"error":"ratelimited"}`, which the Slack SDK raises as `SlackApiException`): the poll routes the two most recent messages once and does not fail (a failed poll would read the range again at every poll). - Without the change the first two fail: `mock://result Received message count. Expected: <5> but was: <2>`. - With the change: camel-slack 9 tests, 0 failures (1 skipped, needs a Slack token). Found with a Lean 4 model of the poll: "a poll routes every message newer than the timestamp" fails for five new messages and a limit of 2 (and with a limit of 1 the second of two messages is never routed by any later poll), and the fix is proved to route exactly the new messages for every `maxResults` >= 1 and to send the same single request as before when no more than `maxResults` messages are new. I then reproduced it with the consumer. # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [x] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for the change (usually before you start working on it). # Apache Camel coding standards and style - [x] I checked that each commit in the pull request has a meaningful subject line and body. - [ ] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. (I built and tested camel-slack, including the formatter and import-sort plugins, and updated the generated catalog and endpoint DSL copies of the option description by hand. I did not run the full root build.) # AI-assisted contributions - [x] If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR description identifies the AI tool used. This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a `Co-Authored-By` trailer. _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
