Is it good design to loop through many users? - SpringBoot - spring

I am looking into good design principles and would just like some feedback.
I want to go through every user in my application that is a patient, check their scheduled activities, see if there is one upcoming and send them an email. It looks a little like this:
List<Patient> listOfAllPatients = patientRepositoryJPA.findAll();
if (listOfAllPatients.size() != 0) {
for (Patient patient : listOfAllPatients) {
user = userRepositoryJPA.findByUsername(patient.getUsername());
Timestamp currentTimeAndDate = new Timestamp(System.currentTimeMillis());
Long closestDate = Integer.toUnsignedLong(31);;
List<Activity> activities = activityRepositoryJPA.findByPatientAndStartDateTimeAfter(patient, currentTimeAndDate);
for (Activity activity : activities) {
Timestamp activityDateAndTime = activity.getStartDateTime();
Long difference = getTimeDifferenceByMinutes(currentTimeAndDate, activityDateAndTime);
if (difference < closestDate) {
LocalDateTime upcomingDate = activity.getStartDateTime().toLocalDateTime();
emailHandler.sendEmail(javaMailSender, "Upcoming Activity Reminder", "The activity, " + activity.getName() + " is starting soon! (" +
upcomingDate.getHour() + ":" + upcomingDate.getMinute() + ")", user);
}
}
}
Now here I loop through every patient in the application and then through each of their activities. If there were many user (millions) surely there would be some bottlenecks or something here.
Does anybody have any advice on how big companies would handle data like this?
Or is what I am doing fine? Thanks.
After some advice, I have improved it to this:
Timestamp currentTimeAndDate = new Timestamp(System.currentTimeMillis());
LocalDateTime add31Minutes = LocalDateTime.now().plus(31, ChronoUnit.MINUTES);
Timestamp noLaterThanDateAndTime = Timestamp.valueOf(add31Minutes);
for (Activity activity : activityRepositoryJPA.findByStartDateTimeBetween(currentTimeAndDate, noLaterThanDateAndTime)) {
Patient patient = activity.getPatient();
LocalDateTime upcomingDate = activity.getStartDateTime().toLocalDateTime();
emailHandler.sendEmail(javaMailSender, "BAA - Upcoming Activity Reminder", "The activity, " + activity.getName() + " is starting soon! (" +
upcomingDate.getHour() + ":" + upcomingDate.getMinute() + ")", patient.getUser());
}
Now I find all activities between now and 31 minutes time in 1 query.

Related

Java 8 - SQL Timestamp to Instant with properly formatted time

I've read through the available q and a on SO, but nothing I have found answers my question of how to format my time in 12hour format.
Following is my code that runs a query on a MySQL database and returns results, checking to see if an appointment is within 15 minutes of login so an alert can pop.
public void apptCheck(int userId) throws SQLException {
// this method checks for an appointment occurring within 15 minutes of login
Statement apptStatement = DBQuery.getStatement();
String apptQuery = "Select apt.start, cs.customerName from DBName.appointment apt "
+ "JOIN DBName.customer cs ON cs.customerId = apt.customerId WHERE "
+ "userId = " + userId + " AND start >= NOW() AND start < NOW() + interval 16 minute";
apptStatement.execute(apptQuery);
ResultSet apptRs = apptStatement.getResultSet();
while(apptRs.next()) {
Timestamp apptTime = apptRs.getTimestamp("start");
ResourceBundle languageRB = ResourceBundle.getBundle("wgucms/RB", Locale.getDefault());
Alert apptCheck = new Alert(AlertType.INFORMATION);
apptCheck.setHeaderText(null);
apptCheck.setContentText(languageRB.getString("apptSoon") + " " + apptTime.toInstant().atZone(ZoneId.systemDefault()));
apptCheck.showAndWait();
}
My result is:
I want the time to display 3:00, not the 19:00 - 06:00. How can I make that happen?
ZonedDateTime zonedDateTime=ZonedDateTime.of(apptTime.toLocalDateTime(),ZoneId.systemDefault());
You can use ZonedDateTime and format the time as you want.
docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html ZonedDateTime has a lot of features you can see all here and you can get the hour, minute, day etc.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss");
String formattedString = zonedDateTime.format(formatter);
if you only want time in 12hour format you can use this
I found the solution which will perform the UTC to local time conversion and then format the time so that the resulting alert is in 12 hour time format without the date or time zone info. Here is the full code:
while(apptRs.next()) {
Timestamp apptTime = apptRs.getTimestamp("start");
// perform time conversion from UTC to User Local Time
ZoneId zidApptTime = ZoneId.systemDefault();
ZonedDateTime newZDTApptTime = apptTime.toLocalDateTime().atZone(ZoneId.of("UTC"));
ZonedDateTime convertedApptTime = newZDTApptTime.withZoneSameInstant(zidApptTime);
ResourceBundle languageRB = ResourceBundle.getBundle("wgucms/RB", Locale.getDefault());
Alert apptCheck = new Alert(AlertType.INFORMATION);
apptCheck.setHeaderText(null);
// set the Alert text and format in 12 hour format
apptCheck.setContentText(languageRB.getString("apptSoon") +
convertedApptTime.toInstant().atZone(ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("h:mm a")) + ".");
apptCheck.showAndWait();
}

Can I use variables across all the threads in the thread groups in jmeter?

I'm trying to create a test plan for rate-limiting behavior.
I set a rule that blocks after X requests per minute, and I want to check that I get response code 200 until I reached the X requests, and from then, to get 429. I created a counter that shared between all the threads, but it seems to be a mess because it's not a thread-safe.
This is my beanshell "once only controller":
String props_pre_fix = ${section_id} + "-" + ${START.HMS};
props.remove("props_pre_fix" + ${section_id}, props_pre_fix);
props.put("props_pre_fix" + ${section_id}, props_pre_fix);
props.put(props_pre_fix + "_last_response_code", "200");
props.put(props_pre_fix + "_my_counter", "0");
and this is the beanshell assertion:
String props_pre_fix = props.get("props_pre_fix" + ${section_id});
//log.info("props_pre_fix " + props_pre_fix);
//extract my counter from props
int my_counter = Integer.parseInt(props.get(props_pre_fix + "_my_counter"));
//extract last response code
String last_response_code = props.get(props_pre_fix + "_last_response_code");
log.info("last_response_code " + last_response_code);
//if last seconds is greater than current seconds it means we are in a new minute - set counter to zero
if(last_response_code.equals("429") && ResponseCode.equals("200")){
log.info("we moved to a new minute - my_counter should be zero");
my_counter = 0;
}
//increase counter
my_counter++;
log.info("set counter with value: " + my_counter);
//save counter
props.put(props_pre_fix + "_my_counter", my_counter + "");
log.info("counter has set with value: " + my_counter);
if (ResponseCode.equals("200")) {
props.put(props_pre_fix + "_last_response_code", "200");
if(my_counter <= ${current_limit}){
Failure = false;
}
else {
Failure = true;
FailureMessage = "leakage of " + (my_counter - ${current_limit}) + " requests";
}
}
else if (ResponseCode.equals("429")) {
props.put(props_pre_fix + "_last_response_code", "429");
if(my_counter > ${current_limit}){
Failure = false;
}
}
I'm using props to share the counter, but I obviously feel that this is not the right way to do it.
Can you suggest me how to do that?
I don't think that it is possible to automatically test this requirement using JMeter Assertions because you don't have access to the current throughput so I would rather recommend considering cross-checking Response Codes per Second and Transactions per Second charts (can be installed using JMeter Plugins Manager)
All the 200 and 429 responses can be marked as successful using Response Assertion configured like:
If for some reason you still want to do this programmatically you might want to take a look at Summariser class source which is used for displaying current throughput in the STDOUT.
Also be informed that starting from JMeter 3.1 you should be using JSR223 Test Elements and Groovy language for scripting.

Amibroker AFL code Buy Sell status is not fetching with if condition

I have AFL which is working fine for crude oil. out of 10 trades, 8 trades are targets hitting. I have code for place orders auto trades. the auto trade code is working fine with other AFL codes but the problem is in below algorithm the BUY and SELL Boolean value is not giving to IF condition. But IIF(Buy .... conditions are working fine.
My main question is why BUY Sell True or false is not working in the last status in AFL. Kindly help me to resolve this.
_SECTION_BEGIN("T+4 day ");
Title = " ..:: duy ::.. - Filter of Stock " + " " + FullName() + " " + Date( ) ;
// 4-Day-Range Switch
prev=AMA2(C,1,0);
d=IIf(C>Ref(Max(Max(H,Ref(H,-20)),Max(Ref(H,-10),Ref(H,-15))),-1),Min(Min(L,Ref(L,-20)),Min(Ref(L,-10),Ref(L,-15))),
IIf(C<Ref(Min(Min(L,Ref(L,-20)),Min(Ref(L,-10),Ref(L,-15))),-1),Max(Max(H,Ref(H,-20)),Max(Ref(H,-10),Ref(H,-15))),PREV));
a=Cross(Close,d);
b=Cross(d,Close);
state=IIf(BarsSince(a)<BarsSince(b),1,0);
s=state>Ref(state,-1);
ss=state<Ref(state,-1);
sss=state==Ref(state,-1);
col=IIf(state == 1 ,51,IIf(state ==0,4,1));
Plot(C,"",Col,128);
Buy=s;
Sell=ss;
PlotShapes( shapeUpArrow * s ,6,0,L);
PlotShapes( shapeDownArrow *ss ,4,0,H);
dist = 0.8*ATR(10);
dist1 = 2*ATR(10);
for( i = 0; i < BarCount; i++ )
{
if( Buy )
{
PlotText( "\nBuy:" + L[ i ] + "\nT= " + (L*1.005) + "\nSL= " + (L*0.9975), i, L[ i ]-dist, colorGreen, colorWhite );
}
if( Sell )
{
PlotText( "Sell:" + H[ i ] + "\nT= " + (H*0.995) + "\nSL= " + (H*1.0025), i, H[ i ]+dist1, colorRed, colorWhite );
}
}
Buy = ExRem(Buy,Sell);
Sell = ExRem(Sell,Buy);
if ( LastValue(Buy)==1)
{
quantity=2;
orderId=placeOrderFuture("MCX", "FUTCOM", ChartSymbol, "BUY", "INTRADAY", "MARKET", quantity, 0, defaultTriggerPrice(), "19-APR-2018", defaultStrategyId(), defaultComments());
//orderId = placeOrderUsingParams(tradeType, AT_ORDER_TYPE, AT_QUANTITY, buyPrice, defaultTriggerPrice(), 1);
}
if ( LastValue(Sell) == 1 )
{
quantity=2;
orderId=placeOrderFuture("MCX", "FUTCOM", ChartSymbol, "SELL", "INTRADAY", "MARKET", quantity, 0, defaultTriggerPrice(), "19-APR-2018", defaultStrategyId(), defaultComments());
//orderId = placeOrderUsingParams("SELL", AT_ORDER_TYPE, AT_QUANTITY, sellPrice, defaultTriggerPrice(), 1);
}
LastValue documentation
With if statements, you need to specify a specific bar. And according to the documentation, LastValue may look into the future. I can't say for sure what's happening with your code, but the loops/if/switch can be tricky. This tutorial Looping in Amibroker might give you some insights into how they work.
You may try SelectedValue instead. If you haven't got any bars selected, it automatically defaults to the last bar. I use this for my realtime trading.
bi = SelectedValue(BarIndex());
if(Buy[bi])
{
...
}
On an unrelated note, your text plots aren't going to plot unfiltered signals, put your ExRem code under your initial Buy and Sell conditions.

how to record the arrival time of an event in esper

I want to record a data processing time in esper and I choose Bollinger Band as example. In Bollinger Band, there is called Moving Average (MA). that MA obtained from the result of calculate the stock price average. In this case, I set win:length(20). So, the MA can be obtained from the result of calculate the stock price average from 20 events that exists in the data window view. The following is code that i created.
public class BollingerBand {
static double startTime, finishTime;
public static void main (String [] args){
Configuration configuration = new Configuration();
configuration.addEventType("Stock", Stock.class);
EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(configuration);
AdapterInputSource source = new AdapterInputSource("BollingerBand.csv");
EPStatement statement = epService.getEPAdministrator().createEPL("insert into Aggregation " +
"select prevcount(symbol), symbol, avg(price) as SimpleMovingAverage, stddev(price) as StandardDeviation, " +
"last(price) as price, last(timestamp) as date from Stock.std:groupwin(symbol).win:length(20)" +
" group by symbol having count(*) >=20");
statement.addListener(new UpdateListener() {
public void update(EventBean[] newEvents, EventBean[] oldEvents) {
// TODO Auto-generated method stub
//System.out.println("Event Receive : "+newEvents[0].getUnderlying());
startTime = System.currentTimeMillis();
System.out.println("\nStart time : " + startTime + " miliseconds\n");
}
});
EPStatement statement2 = epService.getEPAdministrator().createEPL("select symbol, " +
"SimpleMovingAverage + 2*StandardDeviation as UpperBand," +
"SimpleMovingAverage as MiddleBand," +
"SimpleMovingAverage - 2*StandardDeviation as LowerBand," +
"price," +
"4*StandardDeviation/SimpleMovingAverage as Bandwidth," +
"(price - (SimpleMovingAverage - (2 * StandardDeviation))) / ((SimpleMovingAverage + " +
"(2 * StandardDeviation)) - (SimpleMovingAverage - (2 * StandardDeviation))) as PercentB," +
"date from Aggregation");
statement2.addListener(new UpdateListener() {
public void update(EventBean[] newEvents, EventBean[] oldEvents) {
// TODO Auto-generated method stub
//System.out.println("Event Receive : "+newEvents[0].getUnderlying());
finishTime = System.currentTimeMillis();
System.out.println("Start time : " + startTime + " miliseconds");
System.out.println("Finish time : " + finishTime + " miliseconds");
System.out.println("Processing time : " + (finishTime-startTime) + " miliseconds");
}
});
(new CSVInputAdapter(epService, source, "Stock")).start();
}
}
From the above code, time will be recorded if the average has calculated. But what i need is I want the time is recorded when the 20th event and next event enter to data window view. It's as the start time and finish time obtained from bollinger band calculation result. My question is how to record time of the 20th event and in the same time next event enter to the window view data. please help
The CSV adapter doesn't provide a callback when events are sent. You could easily change its code however. Or you could use a different CSV reader and send the events via runtime API.
Maybe have some sort of TickCounter in which there's a map that takes a key value pair of (item_count and timestamp). You update this in your second UpdateListener and of course you can always lookup the item of key 20.
By the way, I've used your Bollinger Band Calculation but using Storm and the EsperBolt. Blogged about it here:
http://chanchal.wordpress.com/2014/07/08/using-esperbolt-and-storm-to-calculate-bollinger-bands/

Entity Framework SaveChanges() first call is very slow

I appreciate that this issue has been raised a couple of times before, but I can't find a definitive answer (maybe there isn't one!).
Anyway the title tells it all really. Create a new context, add a new entity, SaveChanges() takes 20 seconds. Add second entity in same context, SaveChanges() instant.
Any thoughts on this? :-)
============ UPDATE =============
I've created a very simple app running against my existing model to show the issue...
public void Go()
{
ModelContainer context = new ModelContainer(DbHelper.GenerateConnectionString());
for (int i = 1; i <= 5; i++)
{
DateTime start = DateTime.Now;
Order order = context.Orders.Single(c => c.Reference == "AA05056");
DateTime end = DateTime.Now;
double millisecs = (end - start).TotalMilliseconds;
Console.WriteLine("Query " + i + " = " + millisecs + "ms (" + millisecs / 1000 + "s)");
start = DateTime.Now;
order.Note = start.ToLongTimeString();
context.SaveChanges();
end = DateTime.Now;
millisecs = (end - start).TotalMilliseconds;
Console.WriteLine("SaveChanges " + i + " = " + millisecs + "ms (" + millisecs / 1000 + "s)");
Thread.Sleep(1000);
}
Console.ReadKey();
}
Please do not comment on my code - unless it is an invalid test ;)
The results are:
Query 1 = 3999.2288ms (3.9992288s)
SaveChanges 1 = 3391.194ms (3.391194s)
Query 2 = 18.001ms (0.018001s)
SaveChanges 2 = 4.0002ms (0.0040002s)
Query 3 = 14.0008ms (0.0140008s)
SaveChanges 3 = 3.0002ms (0.0030002s)
Query 4 = 13.0008ms (0.0130008s)
SaveChanges 4 = 3.0002ms (0.0030002s)
Query 5 = 10.0005ms (0.0100005s)
SaveChanges 5 = 3.0002ms (0.0030002s)
The first query takes time which I assume is the view generation? Or db connection?
The first save takes nearly 4 seconds which for the more complex save in my app takes over 20 seconds which is not acceptable.
Not sure where to go with this now :-(
UPDATE...
SQL Profiler shows first query and update are fast and are not different for first. So I know delay is Entity Framework as suspected.
It might not be the SaveChanges call - the first time you make any call to the database in EF, it has to do some initial code generation from the metadata. You can pre-generate this though at compile-time: http://msdn.microsoft.com/en-us/library/bb896240.aspx
I would be surprised if that's the only problem, but it might help.
Also have a look here: http://msdn.microsoft.com/en-us/library/cc853327.aspx
I would run the following code on app start up and see how long it takes and if after that the first SaveChanges is fast.
public static void UpdateDatabase()
{
//Note: Using SetInitializer is reconnended by Ladislav Mrnka with reputation 275k
//http://stackoverflow.com/questions/9281423/entity-framework-4-3-run-migrations-at-application-start
Database.SetInitializer<DAL.MyDbContext>(
new MigrateDatabaseToLatestVersion<DAL.MyDbContext,
Migrations.MyDbContext.Configuration>());
using (var db = new DAL.MyDbContext()) {
db.Database.Initialize(false);//Execute the migrations now, not at the first access
}
}

Resources