(control) Message Queue GUI

This commit is contained in:
Viktor Lofgren 2023-08-04 22:05:29 +02:00
parent 912129311d
commit 00eb8b90dc
8 changed files with 210 additions and 77 deletions

View File

@ -84,8 +84,9 @@ public class ControlService extends Service {
var messageQueueRenderer = rendererFactory.renderer("control/message-queue");
var storageDetailsRenderer = rendererFactory.renderer("control/storage-details");
var updateMessageStateRenderer = rendererFactory.renderer("control/dialog-update-message-state");
var updateMessageStateRenderer = rendererFactory.renderer("control/update-message-state");
var newMessageRenderer = rendererFactory.renderer("control/new-message");
var viewMessageRenderer = rendererFactory.renderer("control/view-message");
this.controlActorService = controlActorService;
@ -132,7 +133,7 @@ public class ControlService extends Service {
String payload = rq.queryParams("payload");
persistence.sendNewMessage(recipient,
sender,
sender.isBlank() ? null : sender,
relatedMessage == null ? null : Long.parseLong(relatedMessage),
function,
payload,
@ -141,6 +142,11 @@ public class ControlService extends Service {
return "";
}, redirectToMessageQueue);
Spark.get("/public/message-queue/new", this::newMessageModel, newMessageRenderer::render);
Spark.get("/public/message-queue/:id",
(rq, rsp) -> Map.of("message", messageQueueViewService.getMessage(Long.parseLong(rq.params("id"))),
"relatedMessages", messageQueueViewService.getRelatedMessages(Long.parseLong(rq.params("id"))))
, viewMessageRenderer::render);
Spark.get("/public/message-queue/:id/reply", this::replyMessageModel, newMessageRenderer::render);
Spark.get("/public/message-queue/:id/edit", (rq, rsp) -> persistence.getMessage(Long.parseLong(rq.params("id"))), updateMessageStateRenderer::render);
Spark.post("/public/message-queue/:id/edit", (rq, rsp) -> {
@ -181,10 +187,13 @@ public class ControlService extends Service {
List<MessageQueueEntry> entries;
String mqFilter = "filter=none";
if (inboxParam != null) {
mqFilter = "inbox=" + inboxParam;
entries = messageQueueViewService.getEntriesForInbox(inboxParam, afterId, 20);
}
else if (instanceParam != null) {
mqFilter = "instance=" + instanceParam;
entries = messageQueueViewService.getEntriesForInstance(instanceParam, afterId, 20);
}
else {
@ -200,7 +209,10 @@ public class ControlService extends Service {
Object prev = afterParam == null ? "" : afterParam;
return Map.of("messages", entries, "next", next, "prev", prev);
return Map.of("messages", entries,
"next", next,
"prev", prev,
"mqFilter", mqFilter);
}
private Object complaintsModel(Request request, Response response) {

View File

@ -15,6 +15,9 @@ public record MessageQueueEntry (
int ttl
)
{
public boolean hasRelatedMessage() {
return relatedId > 0;
}
public String ownerInstance() {
if (ownerInstanceFull == null) {
return "";

View File

@ -166,6 +166,37 @@ public class MessageQueueViewService {
}
}
public List<MessageQueueEntry> getRelatedMessages(long relatedId) {
try (var conn = dataSource.getConnection();
var query = conn.prepareStatement("""
(SELECT ID, RELATED_ID, SENDER_INBOX, RECIPIENT_INBOX, FUNCTION, PAYLOAD, OWNER_INSTANCE, OWNER_TICK, STATE, CREATED_TIME, UPDATED_TIME, TTL
FROM MESSAGE_QUEUE
WHERE RELATED_ID = ?
ORDER BY ID DESC
LIMIT 100)
UNION
(SELECT ID, RELATED_ID, SENDER_INBOX, RECIPIENT_INBOX, FUNCTION, PAYLOAD, OWNER_INSTANCE, OWNER_TICK, STATE, CREATED_TIME, UPDATED_TIME, TTL
FROM MESSAGE_QUEUE
WHERE ID = (SELECT RELATED_ID FROM MESSAGE_QUEUE WHERE ID=?)
ORDER BY ID DESC
LIMIT 100)
""")) {
query.setLong(1, relatedId);
query.setLong(2, relatedId);
List<MessageQueueEntry> entries = new ArrayList<>(100);
var rs = query.executeQuery();
while (rs.next()) {
entries.add(newEntry(rs));
}
return entries;
}
catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
private MessageQueueEntry newEntry(ResultSet rs) throws SQLException {
return new MessageQueueEntry(
rs.getLong("ID"),

View File

@ -1,44 +0,0 @@
<!doctype html>
<html>
<link rel="stylesheet" href="/style.css" />
<head><title>Update ID</title></head>
<body>
{{> control/partials/nav}}
<section>
<h1>Update Message State</h1>
<p>Update the of a message in the message queue. This may be useful to prevent an actor
from resuming an action when this is not desirable. Setting an old message to 'NEW' will
erase information about its owner, and inboxes will consider the message new again.</p>
<form method="post" action="/message-queue/{{msgId}}/edit">
<label for="msgId">msgId</label><br>
<input type="text" disabled id="msgId" name="msgId" value="{{msgId}}">
<br>
<label for="relatedId">relatedId</label><br>
<input type="text" disabled id="relatedId" name="relatedId" value="{{relatedId}}">
<br>
<label for="function">function</label><br>
<input type="text" disabled id="function" name="function" value="{{function}}">
<br>
<label for="payload">payload</label><br>
<input type="text" disabled id="payload" name="payload" value="{{payload}}">
<br>
<label for="oldState">current state</label><br>
<input type="text" disabled id="oldState" name="oldState" value="{{state}}">
<br>
<br>
<label for="state">new state</label><br>
<select id="state" name="state">
<option value="NEW">NEW</option>
<option value="ACK">ACK</option>
<option value="OK">OK</option>
<option value="ERR">ERR</option>
<option value="DEAD">DEAD</option>
</select>
<input type="submit" value="Update">
</form>
<p>Note that while setting a message to NEW or in some instances ACK typically causes an Actor
to act on the message, setting a message in ACK to ERR or DEAD will not stop action, but only
prevent resumption of action. To stop a running actor, use the Actors view and press the toggle.</p>
</section>
</html>

View File

@ -1,30 +1,43 @@
<!doctype html>
<html>
<link rel="stylesheet" href="/style.css" />
<head><title>Update ID</title></head>
<head><title>Message Queue | New Message</title></head>
<body>
{{> control/partials/nav}}
<section>
<h1>Create Message</h1>
<form method="post" action="/message-queue/">
<label for="recipientInbox">recipientInbox</label><br>
<input type="text" id="recipientInbox" name="recipientInbox" value="{{recipientInbox}}">
<br>
<label for="senderInbox">senderInbox</label><br>
<input type="text" id="senderInbox" name="senderInbox" value="{{senderInbox}}">
<br>
<label for="relatedId">relatedId</label><br>
<input type="text" id="relatedId" name="relatedId" value="{{relatedId}}">
<br>
<label for="function">function</label><br>
<input type="text" id="function" name="function" value="{{function}}">
<br>
<label for="payload">payload</label><br>
<textarea rows="6" cols="40" id="payload" name="payload">{{payload}}</textarea>
<br>
<br>
<input type="submit" value="Create Message">
<table>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
<tr>
<td><label for="recipientInbox">recipientInbox</label></td>
<td><input type="text" id="recipientInbox" name="recipientInbox" value="{{recipientInbox}}"></td>
</tr>
<tr>
<td><label for="senderInbox">senderInbox</label></td>
<td><input type="text" id="senderInbox" name="senderInbox" value="{{senderInbox}}"></td>
</tr>
<tr>
<td><label for="relatedId">relatedId</label></td>
<td><input type="text" id="relatedId" name="relatedId" value="{{relatedId}}"></td>
</tr>
<tr>
<td><label for="function">function</label></td>
<td><input type="text" id="function" name="function" value="{{function}}"></td>
</tr>
<tr>
<td><label for="payload">payload</label></td>
<td><textarea rows="6" cols="40" id="payload" name="payload">{{payload}}</textarea></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Create">
</td>
</tr>
</table>
</form>
</section>
</body>

View File

@ -3,7 +3,6 @@
<table id="queue" class="table-rh-2">
<thead>
<tr>
<th>Action</th>
<th>State<br>TTL</th>
<th>Msg ID<br>Related ID</th>
<th>Recipient<br>Sender</th>
@ -12,16 +11,15 @@
<th>Created<br>Updated</th>
</tr>
<tr>
<td colspan="7" style="padding: 0.5ch">
<td colspan="6" style="padding: 0.5ch">
<a style="float:right" href="/message-queue/new">[Add Message]</a>
</td>
</tr>
</thead>
{{#each messages}}
<tr>
<td><a href="/message-queue/{{id}}/edit">[Edit]</a></td>
<td>{{stateCode}}&nbsp;{{state}}</td>
<td>{{id}}</td>
<td><a href="/message-queue/{{id}}">{{id}}</a></td>
<td><a href="/message-queue?inbox={{recipientInbox}}">{{recipientInbox}}</a></td>
<td>{{function}}</td>
<td title="{{ownerInstanceFull}}">
@ -30,11 +28,14 @@
<td>{{createdTime}}</td>
</tr>
<tr>
<td>
{{#if senderInbox}}<a href="/message-queue/{{id}}/reply">[Reply]</a>{{/if}}
</td>
<td>{{ttl}}</td>
<td>{{relatedId}}</td>
<td>
{{#if hasRelatedMessage}}
<a href="/message-queue/{{relatedId}}">{{relatedId}}</a>
{{else}}
{{relatedId}}
{{/if}}
</td>
<td><a href="/message-queue?inbox={{senderInbox}}">{{senderInbox}}</a></td>
<td>{{payload}}</td>
<td>{{ownerTick}}</td>
@ -43,9 +44,9 @@
{{/each}}
<tfoot>
<tr>
<td colspan="7" style="padding: 0.5ch">
{{#if prev}}<a href="?after={{prev}}">Prev</a>{{/if}}
{{#if next}}<a href="?after={{next}}" style="float:right">Next</a>{{/if}}
<td colspan="6" style="padding: 0.5ch">
{{#if prev}}<a href="?after={{prev}}&{{mqFilter}}">Prev</a>{{/if}}
{{#if next}}<a href="?after={{next}}&{{mqFilter}}" style="float:right">Next</a>{{/if}}
</td>
</tr>
</tfoot>

View File

@ -0,0 +1,60 @@
<!doctype html>
<html>
<link rel="stylesheet" href="/style.css" />
<head><title>Update ID</title></head>
<body>
{{> control/partials/nav}}
<section>
<h1>Update Message State</h1>
<p>Update the of a message in the message queue. This may be useful to prevent an actor
from resuming an action when this is not desirable. Setting an old message to 'NEW' will
erase information about its owner, and inboxes will consider the message new again.</p>
<form method="post" action="/message-queue/{{msgId}}/edit">
<table>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
<tr>
<td><label for="msgId">msgId</label></td>
<td><input type="text" disabled id="msgId" name="msgId" value="{{msgId}}"></td>
</tr>
<tr>
<td><label for="function">function</label></td>
<td><input type="text" disabled id="function" name="function" value="{{function}}"></td>
</tr>
<tr>
<td><label for="relatedId">relatedId</label></td>
<td><input type="text" disabled id="relatedId" name="relatedId" value="{{relatedId}}"></td>
</tr>
<tr>
<td><label for="payload">payload</label></td>
<td><textarea disabled rows="6" cols="40" id="payload" name="payload">{{payload}}</textarea></td>
</tr>
<tr>
<td><label for="oldState">current state</label></td>
<td><input type="text" disabled id="oldState" name="oldState" value="{{state}}"></td>
</tr>
<tr>
<td><label for="state">new state</label></td>
<td><select id="state" name="state">
<option value="NEW">NEW</option>
<option value="ACK">ACK</option>
<option value="OK">OK</option>
<option value="ERR">ERR</option>
<option value="DEAD">DEAD</option>
</select></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Update" style="float:right">
</td>
</tr>
</table>
</form>
<p>Note that while setting a message to NEW or in some instances ACK typically causes an Actor
to act on the message, setting a message in ACK to ERR or DEAD will not stop action, but only
prevent resumption of action. To stop a running actor, use the Actors view and press the toggle.</p>
</section>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!doctype html>
<html>
<link rel="stylesheet" href="/style.css" />
<head><title>Message Queue | New Message</title></head>
<body>
{{> control/partials/nav}}
<section>
<h1>View Message {{id}}</h1>
{{#with message}}
<table>
<tr><th>Field</th><th>Value</th><th>Action</th></tr>
<tr><td>id</td><td>{{id}}</td><td><a href="new?id={{id}}">[Copy&nbsp;Message]</a></td></tr>
<tr><td>recipientInbox</td><td><a href="/message-queue?inbox={{recipientInbox}}">{{recipientInbox}}</a></td><td></td></tr>
<tr><td>state</td><td>{{state}}</td><td><a href="{{id}}/edit">[Edit&nbsp;State]</a></td></tr>
<tr><td>senderInbox</td><td><a href="/message-queue?inbox={{senderInbox}}">{{senderInbox}}</a></td><td>{{#if senderInbox}}<a href="{{id}}/reply">[Reply]</a>{{/if}}</td></tr>
<tr><td>relatedId</td><td>
{{#if hasRelatedMessage}}
<a href="{{relatedId}}">{{relatedId}}</a>
{{else}}
{{relatedId}}
{{/if}}
</td><td></td></tr>
<tr><td>function</td><td>{{function}}</td><td></td></tr>
<tr><td>payload</td><td>
<textarea disabled rows="6" cols="40" id="payload" name="payload">{{payload}}</textarea>
</td><td></td></tr>
<tr><td>Created</td><td>{{createdTime}}</td></td><td></td></tr>
<tr><td>Updated</td><td>{{updatedTime}}</td></td><td></td></tr>
</tr>
</table>
{{/with}}
{{#if relatedMessages}}
<h2>Related Messages</h2>
<table>
<tr>
<th>ID</th>
<th>Recipient Inbox</th>
<th>Sender Inbox</th>
<th>Function</th>
<th>State</th>
</tr>
{{#each relatedMessages}}
<tr>
<td><a href="{{id}}">{{id}}</a></td>
<td><a href="/message-queue?inbox={{recipientInbox}}">{{recipientInbox}}</a></td>
<td><a href="/message-queue?inbox={{senderInbox}}">{{senderInbox}}</a></td>
<td>{{function}}</td>
<td>{{state}}</td>
</tr>
{{/each}}
</table>
{{/if}}
</section>
</body>
</html>