I am trying to persist my WebsocketSessions on Redis and then succesfully broadcast messages to all my active sessions.
Following the documentation:
https://docs.micronaut.io/latest/guide/index.html#websocket
https://docs.micronaut.io/latest/guide/index.html#sessions
https://micronaut-projects.github.io/micronaut-redis/latest/guide/#sessions
I would expect when I have the following code on my ServerWebSocket, the WebSocket session to be stored automatically on Redis.
#OnOpen
fun onOpen(branchId: Long, session: WebSocketSession) {
session.put(USER_SESSION_KEY, user.id)
session.put(BRANCH_SESSION_KEY, branch.id)
...
session.sendAsync("smth")
}
And then whenever I call the broadcaster, I am expecting the message to be broadcasted to all the open stored-redis-sessions that match the given predicate.
webSocketBroadcaster.broadcastAsync(
webSocketMessage,
shouldSendMessageForSession(order)
)
private fun shouldSendMessageForSession(order: OrdersEntity) = Predicate<WebSocketSession> { session ->
val userId = session[USER_SESSION_KEY, Long::class.java].toNullable() ?: return#Predicate false
val user = userEntityRepository.findById(userId).toNullable() ?: return#Predicate false
val branchId = session[BRANCH_SESSION_KEY, Long::class.java].toNullable() ?: return#Predicate false
return#Predicate order.branchId == branchId && order.canAccessWithUser(user)
}
Sadly this is not happening or I am missing something :( Has anyone found a solution for this?
Is this supported?
If yes, do i need to do something else in order, my broadcaster, to be aware of all the sessions stored on Redis?
Is there a way to serialize|persist a webSocketSession?
Thank you!
Related
I know how to disconnect Sessions from Client Side, but I couldn't find a way to disconnect my session from my Spring Boot Backend. I've already seen the following post:
Disconnect client session from Spring websocket stomp server
This would kinda adress my problem, but I thought maybe there is a much more elegant or easier way to solve my problem, since the above mentioned post is already 8 years old. And still i couldn't get it to work as expected.
Trying to sketch my exact problem:
JS-Client-Side looks like this(pseudo code):
![creates a simple request and sends it to my Spring Backend]
function subscribeToUser(){
request = {};
request.type = "USER";
var user = {};
user.userId = userId;
user.email = email;
request.user = user;
send(request);
}
Server-Side:
Here I detect a Subscribe Event, extract the destination, and check if it is valid. If there is some problem
with the destination I want my server to disconnect from that client.(This should happen in line 122)
#EventListener
private void handleSessionSubscribe(SessionSubscribeEvent event){
String destination =
event.getMessage().getHeaders().get("simpDestination").toString();
Principal p = canSubscribeToThatEndpoint(destination,
event.getUser());
}
private Principal canSubscribeToThatEndpoint(String dest, Principal
user){
if(dest.containt("some invalid thing")){
//close the session from server-side
}else return user;
}
I already tried to follow the mentioned StackOverflow Post but I couldn't get it to run. Also another method would be to send a message from the backend and trigger a disconnect Event in JS. But I think it would be convient(if there is a way) to access current client sessions in Backend and disconnect from them if needed.
I'm getting secret from Azure KeyVault through rest api. At backend, I'm using the azure-keyvault-client which is using retrofit and okhttp3 at behind. My app has been running well for a long time. Now it shows up the exceptions suddenly. Each time the exceptions happens, I restarts the app. Then the exceptions are gone. Everything looks good. What will be the reason that "stream was cancelled"?
Below is the full stack trace.
I have tried to remote debug the app. I found that the exception is thrown when call FramedStream.closeInternal(). The HttpEngine tries to close but source.finished = false and sink.finished = true.
It could either be a local cancel of the stream, or from the server. You can use HTTP/2 Frame logging so see if it's coming from the server.
https://square.github.io/okhttp/debug_logging/#http2-frame-logging
Does the problem persist until restart? If so it's possible that the server is expecting you or OkHttp to close the connection after the cancel, but that isn't expected in that case. So best to debug the frames and then discuss with the server team.
https://github.com/square/okhttp/blob/master/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt
fun enableHttp2() = enable(Http2::class)
fun enableTaskRunner() = enable(TaskRunner::class)
fun enable(loggerClass: String) {
val logger = Logger.getLogger(loggerClass)
if (configuredLoggers.add(logger)) {
logger.addHandler(ConsoleHandler().apply {
level = Level.FINE
formatter = object : SimpleFormatter() {
override fun format(record: LogRecord) =
String.format("[%1\$tF %1\$tT] %2\$s %n", record.millis, record.message)
}
})
logger.level = Level.FINEST
}
}
I want to get the name of the end event in which my process instance ended. I am using Activiti version 7 (spring boot starter of activit). Could anyone help on this?
Hi I also had similar question, and I know this is bit old now, but still ...
You can use HistoryService to get finished process ( presuming you have some id of it )
#Autowired
private HistoryService historyService;
Please consider my code sniplet, which will actually end process due to end of path
Map<String, Object> params = new HashMap<>(); // Some params
Task task = taskService.createTaskQuery()
.processInstanceId(processId)
.singleResult();
taskService.complete(task.getId(), params); //params optional, this ends whole process
List<HistoricVariableInstance> allVars = historyService
.createHistoricVariableInstanceQuery()
.processInstanceId(navTask.getProcessId())
.list();
//return to user all filled in forms etc.
HistoricProcessInstance historicProcess = historyService.createHistoricProcessInstanceQuery().processInstanceId(navTask.getProcessId()).singleResult();
String endId = historicProcess.getEndActivityId(); //This returns ID where your process ended
If id of ending activity is not enough you can go with more digging:
String procDefId = historicProcess.getProcessDefinitionId()
FlowElement flowEl = repositoryService.getBpmnModel(procDefId).getMainProcess().getFlowElements()
.stream()
.filter(flowElement -> flowElement.getId().equals("endId"))
.findFirst()
.orElseThrow(IllegalStateException::new)
flowEl.getName() //your name and other stuff you need
One bottom note: In my case history was not persisted and had to update application properties with spring.activiti.historyLevel=activity and spring.activiti.dbHistoryUsed=true
I am developing corda application using kotlin. I am on webserver spring boot. My requirment is to recieve(postman or any API from outside) XML in requestBody and create IOU(pass) that xml as it is to Flow but i am not able to so. when i define it as a string and pass that xml i am able to do it. but for xml i am struggling. Can anyone help please. Below is my code. am doing anything wrong here. The problem is- i dont get error but it just doesnt work.
#PostMapping(value = ["createTransaction"],consumes = [MediaType.APPLICATION_XML_VALUE],produces = [ MediaType.TEXT_PLAIN_VALUE])
private fun TransactionOne(#RequestBody ()employee:Document, #RequestParam(value = "payload") payload: String, #RequestParam(value = "partyName") partyName: String): ResponseEntity<String> {
val partyX500Name = CordaX500Name.parse(partyName)
val otherParty = proxy.wellKnownPartyFromX500Name(partyX500Name) ?: return ResponseEntity.badRequest().body("Party named $partyName cannot be found.\n")
return try {
val signedTx = proxy.startTrackedFlow(::IOUFlow, employee, otherParty).returnValue.getOrThrow()
ResponseEntity.status(HttpStatus.CREATED).body("Transaction id {$signedTx} committed to ledger.\n")
} catch (ex: Throwable) {
logger.error(ex.message, ex)
ResponseEntity.badRequest().body(ex.message!!)
}
}
This is not clear what does it mean "just doesn't work". You don't have response from "startTrackedFlow"?
What do you see in logs of your nodes? I think the answer is there.
There is not enough information to help you...
I'm writing a web app using grails and spring-security 3.0.3 which requires me to keep a databse record of all successful logins, including the username, time, ip, and sessionId.
I have created a login listener as so(groovy code):
class DpLoginListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
def source = event.getSource()
def principal = source.principal
def details = source.details
TrafficLogin.withTransaction {
new TrafficLogin(userId: principal.id, ipAddress: details.remoteAddress, sessionId: details.sessionId ?: 'remember me').save(failOnError: true)
}
}
}
This fires as expected when a user logs in, but when someone comes back to a site as a "remember me" user, the sessionId is null. Is this the expected behavior? Shouldn't a session be created by the time login has succeeded?
I tried to workaround this by adding a separate SessionCreationEvent listener, which would find the latest databse login record for the user and update that row with the correct sessionId as soon as the session exists, but it seems that this session creation event never fires, and I can't figure out why.
The session creation listener looks like this:
class DpSessionCreatedListener implements ApplicationListener<SessionCreationEvent> {
void onApplicationEvent(SessionCreationEvent event) {
def source = event.getSource()
def principal = source.principal
def details = source.details
TrafficLogin.withTransaction {
def rememberMe = TrafficLogin.find("from TrafficLogin as t where t.userId=? and t.sessionId='remember me' order by t.dateCreated desc", principal.id)
if (rememberMe) {
rememberMe.sessionId = details.sessionId
rememberMe.save(failOnError:true)
}
}
}
}
And a bean is defined for it in my resources.groovy file, in the same manner as the login listener, which fires fine.
Any ideas how to correctly set this sessionId?
Not related to grails, but this SO question may offer a workaround if grails supports it.