-
-
Notifications
You must be signed in to change notification settings - Fork 281
Feat message queue #2056
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feat message queue #2056
Conversation
…or acknowledgment before the next is sent
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds an optional message queue feature to automatically retry failed text messages when target nodes become reachable, with UI controls and persistent storage.
- Introduces string resources and settings for the queue
- Extends UI components to display queued-for-retry status and allow manual retry/cancel
- Implements database entities/DAO, retry strategy, and service integration for background processing
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
app/src/main/res/values/strings.xml | Added message queue text, status labels, and actions |
app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt | Show “queued for retry” label and Schedule icon |
app/src/main/java/com/geeksville/mesh/ui/message/MessageList.kt | Updated DeliveryInfo dialog for retry and cancel |
app/src/main/java/com/geeksville/mesh/service/RetryStrategy.kt | New exponential backoff logic and status descriptions |
app/src/main/java/com/geeksville/mesh/service/MessageQueueManager.kt | Core queue management, enqueue/dequeue, processing |
app/src/main/java/com/geeksville/mesh/service/MeshService.kt | Hooks into service for network/node events |
app/src/main/java/com/geeksville/mesh/database/entity/QueuedMessage.kt | New Room entity for queued messages |
app/src/main/java/com/geeksville/mesh/database/dao/MessageQueueDao.kt | DAO for queue operations |
app/src/main/java/com/geeksville/mesh/database/MeshtasticDatabase.kt | Registered new entity and DAO |
app/src/main/java/com/geeksville/mesh/database/DatabaseModule.kt | Provided MessageQueueDao |
app/src/main/java/com/geeksville/mesh/MainActivity.kt | Settings dialog integration for toggling the queue |
app/src/main/java/com/geeksville/mesh/DataPacket.kt | Added MessageStatus.QUEUED_FOR_RETRY |
Comments suppressed due to low confidence (1)
app/src/main/java/com/geeksville/mesh/ui/message/MessageList.kt:107
- R.string.delete is not defined in strings.xml and will cause a build error. Consider replacing this with the existing
R.string.message_queue_cancel_retry
("Remove from Queue") or adding adelete
string resource if intended.
) { Text(text = stringResource(id = R.string.delete)) }
*/ | ||
fun getRetryStatusDescription(queuedMessage: QueuedMessage, currentTime: Long): String { | ||
if (currentTime - queuedMessage.queuedTime > MAX_MESSAGE_AGE_MILLIS) { | ||
return "Message expired (24h limit reached)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User-facing strings are hard-coded in the retry status description. For localization and consistency, move these literals into strings.xml and reference them with string resources.
Copilot uses AI. Check for mistakes.
* Generate a new packet ID for retry attempts | ||
*/ | ||
private fun generatePacketId(): Int { | ||
return Random().nextInt() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Random().nextInt() can generate negative values, which may produce invalid packet IDs. Consider bounding the result (e.g., abs(random.nextInt())
) or using a positive-range generator to ensure packet IDs are always non-negative.
return Random().nextInt() | |
return Math.abs(Random().nextInt()) |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using Random
entirely - maybe use a UUID
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We definitely don't want to modify the current 18.json
db schema.
If you revert the changes to the schema json files (and delete 19) and rebuild - it should just generate a new 19.json schema with the migragtions needed for 18-19 and not modify 18.json
*/ | ||
fun getRetryStatusDescription(queuedMessage: QueuedMessage, currentTime: Long): String { | ||
if (currentTime - queuedMessage.queuedTime > MAX_MESSAGE_AGE_MILLIS) { | ||
return "Message expired (24h limit reached)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep - let's extract these so they can be localized.
I shared your PR with the other contributors on discord and it's generated a lot of excitement, and also some implementation feedback:
|
Thanks for the feedback. I'll clean this up per your suggestions. I originally made this so you needed to hit 'Retry' in the dialog to enter the queue, but it felt like an unnecessary extra step given I know that I always want the queue behaviour. Are you suggesting that the queue is always enabled, and a message enters the queue when you click 'Retry' in the retry dialog? Should I remove the setting from the main menu? About backoff times. What do you suggest for backoff times? I pulled those out of the air. Presumably if this feature is being utilized the user is not in a congested mesh, but we understandably can't expect everyone to use the feature with consideration of wider impacts. (15m 1h 3h 6h 12h)? |
Yes, the suggested flow would be the queue is always available, and messages to be added to the queue as an additional option from the retry dialog. (Also removing the main menu setting since it's always "on"). Manual per-message opt-in allows us to mitigate initial impact until we better understand it. As for the timing, let's roll with it the way it currently is. We can tune it in later iterations. |
There is equally inherent 3-attempt logic at the radio level while trying to find a recipient for either direct delivery or relayed DM. I would also ensure we persist this as a DM only feature, not something we have available for channel messages. |
hi @Stephen-S-H - any plans to continue work on this? |
Yes, I'm time poor though. I'll update my PR in the next week I think.
…On Wed, 18 Jun 2025 at 22:18, James Rich ***@***.***> wrote:
*jamesarich* left a comment (meshtastic/Meshtastic-Android#2056)
<#2056 (comment)>
hi @Stephen-S-H <https://github.com/Stephen-S-H> - any plans to continue
work on this?
—
Reply to this email directly, view it on GitHub
<#2056 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/A3KPXZET6QAUBB5UTCHR4O33EFKIJAVCNFSM6AAAAAB62Z2JXCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDSOBTHE3DQMZYGI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Sounds good, thanks! |
This feature adds an optional message queue that stores messages until a node is reachable and then retries sending.
#1979 (comment)
Enable the message queue


Send a message to a node that is not reachable

When Max Retransmission Attempts are reached, the message enters the queue:

Tap the clock icon for more info, to manually retry, or to delete the message from the queue (deletes message entirely)

When the node comes online and the app receives a packet from the node, it retries the send.

This seems to work on my devices nicely, but I'm new to both Meshtastic and Kotlin so please take a careful look over this PR to make sure I'm not doing anything unwise here.