Is It Necessary to Add Ack Mechanism To Websocket Server? - go

We are building a websocket server via golang+gin+json+gorilla websocket to push messages from server side to browser.
We plan to provide frontend with some subscription command, which means messages from server side will be sent to those users who subscribed target topic.
My confusion is whether we need add Ack mechanism here? For example, when client subscribe one topic, the server saved this mapping: user --> topic.
Is it necessary for the server to send a response for each subscription request to clients (Like that we do for an RPC request)? And how to do that? Below is my consumption
type MsgHeader struct {
ReqId string `json: reqId`
Cmd string `json: cmd`
// either of "req" or "rsp"
// is it necessary to have this field???
Type string `json: type`
}
I mean the application level acknowledgement, like what we do for RPC requests. For RPC request, we send responses even when the response itself is empty, something like:
type SubscriptionRsp struct {
Code int
Msg string
Data interface{}
}

No, it's not necessary.
The Websocket specs (RFC 6455) does not mandate this.
A data frame MAY be transmitted by either the client or the server at
any time after opening handshake completion and before that endpoint
has sent a Close frame
Nothing else about acknowledging messages is said in the Sending and Receiving Data section.
Therefore any ACK is entirely an implementation detail of your application. It may be useful if you develop a resilient client that retries failed messages, where "failed" could a message that is successfully sent to the server but not processed as expected.

Related

Spring TCP Integration only reads every 30+ seconds

I'm having an issue making a TCP Server using Spring-Integration.
I've set my server up to accept TCP Connections from a black box client. The client will connect to the server and start periodically sending it string data.
What I'm seeing is after the connection is established (I get confirmation from the client side) I don't receive a print statement on the server until about 30 seconds have passed, where I get 5 messages all at once.
I've monitored incoming data over wireshark and the client is sending data at regular intervals, but the server doesn't read from the incomingStream frequently enough. Is there a way to configure the TcpServer that it reads data from incoming clients more frequently?
fun flow() = IntegrationFlows.from(
Tcp.inboundAdapter(Tcp.nioServer(port).serializer(ByteArrayRawSerializer()).deserializer(ByteArrayRawSerializer()))
.errorChannel(errorChannel())
)
.transform(ObjectToStringTransformer())
.handle { payload: String, headers: MessageHeaders ->
println(payload)
}
.get()
The ByteArrayRawSerializer uses the socket close to detect the end of a message.
TCP is a streaming protocol and, if you want to send multiple messages over the socket, you need to delimit the data somehow so the server can determine when one message ends and the next one starts. See the documentation.
TCP is a streaming protocol. This means that some structure has to be provided to data transported over TCP so that the receiver can demarcate the data into discrete messages. Connection factories are configured to use serializers and deserializers to convert between the message payload and the bits that are sent over TCP. This is accomplished by providing a deserializer and a serializer for inbound and outbound messages, respectively. Spring Integration provides a number of standard serializers and deserializers.
...
The ByteArrayRawSerializer, converts a byte array to a stream of bytes and adds no additional message demarcation data. With this serializer (and deserializer), the end of a message is indicated by the client closing the socket in an orderly fashion. When using this serializer, message reception hangs until the client closes the socket or a timeout occurs.
My guess is the client is not closing the connection after sending the message and there is a 30 second SO timeout (either on the client or server - you don't show your connection factory configuration).

Nats.io QueueSubscribe behavior on timeout

I'm evaluating NATS for migrating an existing msg based software
I did not find documentation about msg timeout exception and overload.
For Example:
After Subscriber has been chosen , Is it aware of timeout settings posted by Publisher ? Is it possible to notify an additional time extension ?
If the elected subscriber is aware that some DBMS connection is missing and cannot complete It could be possible to bounce the message
NATS server will pickup another subscriber and will re-post the same message ?
Ciao
Diego
For your first question: It seems to me that you are trying to publish a request message with a timeout (using the nc.Request). If so, the timeout is managed by the client. Effectively the client publishes the request message and creates a subscription on the reply subject. If the subscription doesn't get any messages within the timeout it will notify you of the timeout condition and unsubscribe from the reply subject.
On your second question - are you using a queue group? A queue group in NATS is a subscription that specifies a queue group name. All subscriptions having the same queue group name are treated specially by the server. The server will select one of the queue group subscriptions to send the message to rotating between them as messages arrive. However the responsibility of the server is simply to deliver the message.
To do what you describe, implement your functionality using request/reply using a timeout and a max number of messages equal to 1. If no responses are received after the timeout your client can then resend the request message after some delay or perform some other type of recovery logic. The reply message should be your 'protocol' to know that the message was handled properly. Note that this gets into the design of your messaging architecture. For example, it is possible for the timeout to trigger after the request recipient received the message and handled it but before the client or server was able to publish the response. In that case the request sender wouldn't be able to tell the difference and would eventually republish. This hints that such type of interactions need to make the requests idempotent to prevent duplicate side effects.

How can client get notified of completion status of the request sent to server?-Winsock

I am in the middle of learning Winsock and came across a conceptual problem in getting notification of request completion status from server. As client is designed only to send while server to receive, is there any way that a client can be notified? Thanks.
The server side socket that is used when you call recv can also be used to send data. Remember that the SOCKET struct that you get when you accept a client on the server is the same as the SOCKET struct on the client side that is used to connect. Thus after receiving data from the client, you can send a reply like
send(s, res_str, strlen(res_str), 0);
Where res_str is your response string. Technically res_str is strlen(res_str) + 1 bytes in size but we don't want the null character.

stomp message acknowledgement from client

I am using spring/stomp/websocket framework to notify users of messages asynchronously. I have done this successfully. However, I would be get ACK from the client so that some server side action can take place when this is done.
The flow is roughly as flows:
Service notifies a specific user about a decision and updates a record in the DB with status = "notified"
Client receives the message (using stompClient.subscribe(...))
Client acknowledges that the message was received.
The service "knows" that this message was acknowledged and updates the status to "ACK" in the DB.
stompClient.connect({login:'guest', passcode:'guest'},
function(frame) {
setConnected(true);
**var headers = {ack: 'client'};**
...
stompClient.subscribe('/user/guest/response',function(notification) {
//doSomething
}), **headers**);
}
In the service, the message is sent:
this.messagingTemplate.convertAndSendToUser(user, "/response",msg, map);
Is there a way to handle the client ACK on the server side?
Alternatively, I tried to do a
stompClient.send("/app/response/ack/"+messageId);
on the client, in the method that handles the subscription, but in vain.
Can someone please tell me what is standard way to handle acknowledgments? I have been struggling with this for a a couple of days and any thoughts would be very helpful.
Thanks!
Use the ACK frame as per spec. The server sends an ack:some_id header, the client uses that some_id in the ACK frame.
The answer is no for simple broker.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
The simple broker is great for getting started but supports only a
subset of STOMP commands (e.g. no acks, receipts, etc.), relies on a
simple message sending loop, and is not suitable for clustering. As an
alternative, applications can upgrade to using a full-featured message
broker.

message service with relay behaviour

I'm designing a distributed network of sensing device. These devices will generate logs and send them to a central database. I'm using JMS for transporting log messages. The main database server will be running MDB(Message Driven Bean) to process incoming messages. The clients are sending data with GPRS. The problem is I don't want my clients to process network problems. I need some relay service that runs locally on client machine and gets the message from client immediately without blocking it and try on behalf of it.(if network is down, try sending again after some time).
message is a simple java object:
public class Message {
public int x;
public int y;
public int z;
}
client:
Message msg = new Message();
while (True) {
/* sense data */
msg = get_data_from_environment();
/* send data to local relay service
* This is non blocking call */
relay_service.send(msg);
}
local relay service:
while (True) {
/* get message from local client */
msg = get_message_from_local_client();
result = send_msg_to_JMS_server(msg);
/* if not successful, persist it on a local queue and try some other time */
if (result.is_sent() != True)
store_msg_on_disk(msg);
}
Is there a message service like this or I should write relay service myself?
is this good to use JMS in this case? Should I design my own socket level protocol to send messages?
EDIT
Is there a message service like this or I should write relay service myself?
Typically these type of relay services you have to code your self, unless you are able to find a software that does exactly what you want it to do. This is not unusual to be done in these cases.
Is this good to use JMS in this case?
Yes, JMS is a very good solution to use as a middleware. You can have many clients connect to JMS and send messages to it. While you have a server program running reading the messages off the JMS and processing it and handling network problems if there are any. Also as a bonus the server program and send back messages to the client in case of complete failure.
Should I design my own socket level protocol to send messages?
I still do not know what kind of messages you want to send. If you are using a standard transport like SMTP or SMS or HTTP or something like that, there are libraries to help you send and verify delivery. If you have to send using a custom protocol then you would have to write you own socket level code.
Seeing your code examples shows me that you want to know if your client was successful in sending his message to the JMS. If it was not sent then save to disk and try again later.
JMS server will auto-acknowledge if the message received. You can check this from the JMS message or if it fails you will get a JMSException. If you save messages on disk you will need to know when to re-send them. You would need a timer or re-send on next message to send.

Resources