Spring: howto show log messages to the user? - spring

In my Spring/Hibernate/MVC application I implement some long running functions. In this case I would like to inform the user about the status.
I wonder, if I can get certain log4j messages to the frontend, like:
DEBUG d.t.webapp.services.StageServiceImpl - Fetching result
DEBUG d.t.webapp.services.StageServiceImpl - loaded 1000 rows
DEBUG d.t.webapp.services.StageServiceImpl - loaded 1000 rows
DEBUG d.t.webapp.services.StageServiceImpl - loaded 1000 rows
DEBUG d.t.webapp.services.StageServiceImpl - loaded 994 rows
Those message should appear to the frontend step-by-step, as they are produced by the backend, with minimal delay. Is that possible or are there better solutions for this requirement?

Or why not just use something like this:
1# Create a controller to provide you with last status of your worker
#RestController
#RequestMapping(value = "/worker")
public WorkerStatusProviderController {
#Autowired
WorkerStatusProvider workerStatusProvider;
#RequestMapping(value = "/status/{id}", method = RequestMethod.GET)
public new ResponseEntity<WorkerStatus> getStatus(#PathVariable("id") long workerId){
//retrieve last worker status
WorkerStatus lastStatus = workerStatusProvider.getLastStatus(workerId);
//send worker status to front
return new ResponseEntity<WorkerStatus>(lastStatus, HttpStatus.OK);
}
}
2# In frontend use Ajax to call this controller every 2 or 3 seconds and display the last status to your user.
//call /worker/status/id every 2 seconds
setInterval(function(){
$.get("/worker/status/100", function(workerStatus, status) {
//display worker status to the user
alert("workerStatus: " + workerStatus);
});
}, 2000);

Related

Send updates or progress in Spring Controller before response

I have a form that allows users to upload CSV files which subsequently uses Superagent to make a POST call to a controller in the backend which parses through the file and executes batch inserts into our tables. I would like to implement a progress bar on the front-end side that listens for updates from the controller to show the progress of the parsing/inserts. On the front end I'm using React and currently making the call like this:
request.post('/api/uploadFile')
.send(csvFile)
.on('progress', function(e) {
console.log('Percentage done: ', e.percent);
})
.end((err, resp) => {
if (err) {
$("#loading").hide();
console.log("Error in file upload");
console.error(err);
alert("Failed to upload. " + err + "\n (" + err.status + ") " + resp.text);
}
else {
$("#loading").hide();
console.log(resp);
alert("Success. " + resp.text);
return resp;
}
});
}
The progress event listener automatically shows 100% as soon as I send the file, which is incorrect (the sending appears to be instant but it doesn't actually know how much is reached from the other end until there's a response). On the backend I have a controller like this:
#RequestMapping(value="/api/uploadFile", method=RequestMethod.POST)
public #ResponseBody ResponseEntity<String> handleFileUpload(#RequestParam("file") MultipartFile file){
if (!checkCSV(file)) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body("Not CSV");
}
if (file.isEmpty()) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body("File is empty");
}
MySQLAccess db = new MySQLAccess();
File fileToParse = convertToFile(file);
/* Call helper function that parse CSV file & execute batch inserts & creates join tables */
return ResponseEntity.ok("File was uploaded.");
}
I would like to interleave progress status (which I can set) in my controller that would update the frontend regarding which step the file upload is at: the parsing/batch inserts/table creations, etc. I would like to do this because my app is currently deployed on Heroku and I keep hitting request timeouts because the file upload process takes around 1 minute, which is over the 30 second window Heroku sets for H12 request timeouts if it doesn't receive a single byte back to the client (I'm assuming if I'm sending back updates it might prevent these timeouts?). Does anyone have any suggestions on how to send updates from my controller to update the progress before the response is sent back?

email read from EWS (exchange web service) server cannot process this request error c#

I have a task where i need to check the emails delivered to my mailbox and read them ,based on subject i have to do some task. But for demo purpose I have put only the basic functionality of just updating the email read status
The basic connection and creating service object everything is fine:
///////////
NetworkCredential credentials = new NetworkCredential(securelyStoredEmail, securelyStoredPassword);
ExchangeService _service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
_service.Credentials = credentials;
_service.AutodiscoverUrl("User1#contoso.com");
/////////////////////////
Here Everything works fine. However I will invoke the below method for every 60s using observable event of reactive linq. THis is to go and poll the my emailbox and read 100 emails for every 60 seconds.
Everything works fine till sometime. Sometimes when the control reaches the line of code inside parallel.foreach loop, it shows error message like 'server cannot process this request now. Please try later' something like this. THis error comes exactly at the line
var email = EmailMessage.Bind(_service, findItemsResult.Id, emailProps);
so for every 60 seconds, i will get this error sometimes.sometimes it works fine.
Below is the method which is executed for every 60seconds. Its like i try to read the emails from "myaccount.com" for every 60s and i vil get the error 'server cannot process'.
internal void GetEmailsFrommymailbox()
{
try
{
var view = new ItemView(100);
var userMailbox = new Mailbox(userMailbox);
var folderId = new FolderId(WellKnownFolderName.Inbox, userMailbox);
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And,
new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
var findResults = _service.FindItems(folderId, sf, view);
var emailProps = new PropertySet(ItemSchema.MimeContent, ItemSchema.Body,
ItemSchema.InternetMessageHeaders);
Parallel.ForEach(findResults, findItemsResult =>
{
///////////// this is the line where i get error////////
var email = EmailMessage.Bind(_service, findItemsResult.Id, emailProps);
//// above is the place where i get error
var emailMatching = email;
try
{
email.IsRead = true;
email.Update(ConflictResolutionMode.AutoResolve);
}
catch (Exception emailreadFromBccException)
{
Logger.Warn(emailreadFromBccException + " Unable to update email read status");
}
});
}
}
Your getting that error because you being throttled https://msdn.microsoft.com/en-us/library/office/jj945066%28v=exchg.150%29.aspx and your being throttled because you code isn't very efficient.
Instead of doing
Parallel.ForEach(findResults, findItemsResult =>
{
///////////// this is the line where i get error////////
var email = EmailMessage.Bind(_service, findItemsResult.Id, emailProps);
You should use LoadPropertiesFromItems http://blogs.msdn.com/b/exchangedev/archive/2010/03/16/loading-properties-for-multiple-items-with-one-call-to-exchange-web-services.aspx . Which will reduce the number of call you need to make to the server.
I would also suggest you use Streaming notification https://msdn.microsoft.com/en-us/library/office/hh312849%28v=exchg.140%29.aspx?f=255&MSPPError=-2147217396 which will mean you won't need to poll the server every 60 seconds and just take an action when a new item arrives.
Cheers
Glen

spring websocket notification

Ok here i'm , i'm right now following the guides on spring site but i'm having problem on how to deliver a notification to only one user using WebSocket, i'm following this guide https://spring.io/guides/gs/messaging-stomp-websocket/ .
What I want is: i have 2 users, both of them subscribe to process1... User1 need to let the server process his pass...now i want that the server will deliver the notification only to User1...
#Controller
public class ProcessController {
#MessageMapping("/ProcessOwner/approve/{pass}")
#SendTo("")
public String notifica(#DestinationVariable String pass)throws Exception{
return "ok"+pass;
}
}
Now what should i write in the #SendTo field to deliver the answer only to user1 ? if ill write /Process/process1 both user1 and user2 will receive the message....
You ca use the sufix. It's send to every unique client.
When you subscribe in the js code:
client.connect('guest', 'guest', function(frame) {
var suffix = frame.headers['queue-suffix'];
client.subscribe("/queue/error" + suffix, function(msg) {
// handle error
});
client.subscribe("/queue/position-updates" + suffix, function(msg) {
// handle position update
});
});
On the server side you can use #ReplyToUser or the message template
String user = "fabrice";
String queue = "/queue/position-updates";
this.messagingTemplate.convertAndSendToUser(user, queue, position);
See more here: http://assets.spring.io/wp/WebSocketBlogPost.html (section: Sending Messages To a Single User)

What is the proper way to add Timer (for Task Schedule) in Spring 3+Tiles based web application?

I want to know if there is any proper way to add timer for task schedule (it will be count up) in Spring 3 + Tiles that works accurate. I have tried many options like jquery timer + (Client side) Quartz (Server side Threading), But though it is not accurate and somewhat we can say it is bad practice for web application.
What I exactly want (want to manage) is in my Web application(Spring 3 + Tiles), When user Click on Timer start, It should be started at client side and timer should be continued until user click on stop, however user could do any other things (Like navigation to any other pages) in web application but timer should be working in static way. There are many issues as if only I implement timer at client side (using cookies ,jquery session client side) than I have to manage if user navigate to another page then again timer will have to start from previous time that has been stored in cookies but doing this results in loss of seconds during request response processes.So I tried also to implement server side timer using quartz but again I have to sync it with client side timer at every click in web application . So again it is bad practice what I feel.
So Is there any thing that I can introduce in Spring 3 + tiles that can be static and can hold timer in static way.
Thanx in Advance.
Ok so you need Server Push in simple words.You can use Atmosphere for acheving this.
For integrating atmosphere with Spring MVC you can check this sample spring-web-mvc-atmosphere.after integration you just need to do this on your server side.
#RequestMapping(value = "/websockets", method = RequestMethod.GET)
#ResponseBody
public void websockets(final AtmosphereResource event) {
AtmosphereUtils.suspend(event);
final Broadcaster bc = event.getBroadcaster();
bc.scheduleFixedBroadcast(new Callable<String>() {
public String call() throws Exception {
return (new Date()).toString();
}
}, 1, TimeUnit.SECONDS);
}
And from client side:
function startTimer() {
var callbackAdded = false;
function callback(response)
{
$.atmosphere.log('info', ["response.state: " + response.state]);
$.atmosphere.log('info', ["response.transport: " + response.transport]);
if (response.transport != 'polling' && response.state != 'connected' && response.state != 'closed') {
$.atmosphere.log('info', ["response.responseBody: " + response.responseBody]);
if (response.status == 200) {
var data = response.responseBody;
if (data) {
$("#date").text(data);
}
}
}
}
$.atmosphere.subscribe("${pageContext.request.contextPath}/user/websockets",
!callbackAdded? callback : null,
$.atmosphere.request = {transport: 'websocket'});
connectedEndpoint = $.atmosphere.response;
callbackAdded = true;
};
Just suspend the get request and broadcast the current time perodically and you can extend this according to you need I have just given you a raw idea.Hope this helps.

Multiple ajax get requests of same route but different query string

I have had this for a couple of days now.
I have a simple search form. When form is submitted the server searches for some data from another server and return data to the screen. When the submit completes it gets some javascript from the server based on the results returned from the search. the javascript then makes multiple concurrent jquery get requests, lets say 4, to the asp.net mvc3 webapp.
I have demonstrated that all the get requests fire at the same time in Firebug but when debugging my app with VS the breakpoints only get hit once the previous request completes.
The actions are the same but the querys are different; ie
/Home/Details/040801
/Home/Details/040802
/Home/Details/040803
So these are different URLs and, from what i found out, FF should treat them differently.
So my questions are:
Am I missing something obvious?
Does IIS have some funny blocking on the same route?
Is it a session cache issue? I am locking lock (lockobject){} on writes to the common session variables.
Im not using ViewBag or TempData.
The page load times, even when everything is cached in the Session, are still noticeably synchronous.
Windows Server 2008 R2
Using IIS 7.5
ASP.NET MVC 3
VS2010 Chrome or FF browser
I have my routes set up as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
routes.MapRoute("Details", "{controller}/{action}/{id}/{booking}", new { id = UrlParameter.Optional, booking = UrlParameter.Optional});
Nothing special there as you can see.
Sample code from one of the blocked routes:
public ActionResult Details(string id, bool booking = false)
{
if (booking)
{
return BookingDetails(id, true);
}
Dictionary<string, FlightDetails> detailDic;
string scenarioInput;
lock (DetailsLock)
{
if (Session["DetailDic"] == null)
{
Session["DetailDic"] = new Dictionary<string, FlightDetails>();
}
detailDic = (Dictionary<string, FlightDetails>)Session["DetailDic"];
}
if (detailDic.ContainsKey(id))
{
return PartialView("Details", detailDic[id]);
}
lock (GuidLock)
{
if (Session["DetailGuids"] == null)
{
Session["DetailGuids"] = new Dictionary<string, string>();
}
scenarioInput = ((Dictionary<string, string>)Session["DetailGuids"])[id];
}
// query results list
string queryText = string.Format("<View><Query><Where><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">OUT {0}</Value></Eq></Where></Query></View>", scenarioInput);
ListItemCollection oList;
int counter = 0;
do
{
oList = SharepointHelper.GetListFromSharepoint("ListName", queryText, ClientContext);
counter++;
Thread.Sleep(1000);
} while (oList.Count == 0 && counter <= Timeout);
if (oList.Count == 0)
{
return PartialView("Details", (object)null);
}
var item = oList[0];
FlightDetails flightDetails = CreateFlightDetails(id, scenarioInput, item);
lock (DetailsLock)
{
detailDic.Add(id, flightDetails);
}
return PartialView("Details", flightDetails);
}
when using session object in server-side your async calls wait for session object released by other request. Becuase of this async ajax calls act like sync. You have to use session as readonly in that action.
Add this attribute to action you call if you dont write anything to session.
[SessionState(SessionStateBehavior.ReadOnly)]

Resources