Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trip monitor timing refactor #75

Merged
merged 13 commits into from
Oct 14, 2020
Merged

Trip monitor timing refactor #75

merged 13 commits into from
Oct 14, 2020

Conversation

evansiroky
Copy link
Contributor

Checklist

  • Appropriate branch selected (all PRs must first be merged to dev before they can be merged to master)
  • Any modified or new methods or classes have helpful JavaDoc and code is thoroughly commented
  • The description lists all applicable issues this PR seeks to resolve
  • The description lists any configuration setting(s) that differ from the default settings
  • All tests and CI builds passing

Description

This PR refactors the timing aspects of the trip monitor. The previous implementation was a little naive and had trouble calculating the proper time to check since it didn't use information from previous checks. This PR changes that and now will store the next upcoming itinerary for a trip and will use that check as a baseline for determining if a trip check should be skipped and how long to wait before the lead time. This results in making requests on the proper date and tracking a trip all the way until the end even if it goes longer than scheduled.

So, this PR addresses both the change in monitored trip monitoring window settings and Recalculate for current day (plan trip at the appropriate time) items in #70.

Here is a summary of changes:

  • Clarifies the purpose of a few variables by renaming them
    • YYYY_MM_DD -> DEFAULT_DATE_FORMAT_PATTERN
    • org.opentripplanner.middleware.otp.response.Response -> org.opentripplanner.middleware.otp.response.OtpResponse
  • Using mocked date/time for items that create Date objects
  • JourneyState
    • now saves just the matchingItinerary instead of an otpResponse
    • also saves the target date for easier OTP querying
    • renames some variables to have ...millis to make it clear that the values are milliseconds
  • MonitoredTrip
    • Constructor automatically sets the tripTime from the query params
    • Adds an isInActive method for checking if the trip is never active
    • Adds method getTimezoneForTargetLocation and associated helper methods to get the appropriate timezone to calculate a target time with based off of whether the trip is departing at or arriving by
    • Adds convenience methods getHour and getMinute.
  • Itinerary/Leg
    • replaces equality/hashcode check of startTime and endTime with duration instead. This is probably a temporary fix and more nuance will be needed in the future especially when dealing with realtime itineraries
  • CheckMonitoredTrip
    • Prefixes all log outputs in the class with the trip ID. (this required a change to the logback.xml file)
    • Refactors a lot of methods to not be static and instead be instance methods to avoid repetitive arguments/variables
    • Refactored timing checks to rely heavily on refactored implementation of shouldSkipMonitoredTripCheck. This method now calculates itineraries if none have been calculated before in order to have a baseline to use when determining if a formal check of the trip is warranted that might result in notifications being sent out.
    • Introduces new method calculateNextItinerary which advances the trip to the appropriate date and sends off a request to OTP to obtain a new baseline itinerary to compare with in future checks of the trip.
  • TestUtils
    • Adds to the mock OTP server by allowing a series of mock responses to be added for individual test cases
  • CheckMonitoredTripTest
    • significantly modifies the testSkipMonitoredTripCheck ParameterizedTest to check a variety of test cases that test various aspects of the shouldSkipMonitoredTripCheck. These tests sometimes will result in requests to the mock OTP server and as such mock responses are created. These tests hit a lot of the logic around generating OTP queries and therefore, the draft test of canGenerateTripPlanQueryParams was removed.

@codecov-commenter
Copy link

codecov-commenter commented Sep 16, 2020

Codecov Report

Merging #75 into dev will increase coverage by 3.38%.
The diff coverage is 53.12%.

Impacted file tree graph

@@             Coverage Diff              @@
##                dev      #75      +/-   ##
============================================
+ Coverage     38.74%   42.13%   +3.38%     
- Complexity      264      297      +33     
============================================
  Files            81       81              
  Lines          2261     2307      +46     
  Branches        258      264       +6     
============================================
+ Hits            876      972      +96     
+ Misses         1301     1231      -70     
- Partials         84      104      +20     
Impacted Files Coverage Δ Complexity Δ
...nner/middleware/controllers/api/ApiController.java 34.45% <0.00%> (ø) 4.00 <0.00> (ø)
...eware/controllers/api/MonitoredTripController.java 19.04% <0.00%> (-9.53%) 2.00 <0.00> (ø)
...iddleware/controllers/api/OtpRequestProcessor.java 21.27% <0.00%> (ø) 3.00 <0.00> (ø)
...tripplanner/middleware/otp/response/Itinerary.java 77.41% <0.00%> (+8.66%) 7.00 <0.00> (+2.00)
...g/opentripplanner/middleware/otp/response/Leg.java 55.17% <0.00%> (+5.17%) 5.00 <0.00> (+1.00)
...anner/middleware/persistence/TypedPersistence.java 47.82% <0.00%> (ø) 14.00 <0.00> (ø)
.../opentripplanner/middleware/otp/OtpDispatcher.java 79.31% <33.33%> (+68.59%) 4.00 <0.00> (+3.00)
...entripplanner/middleware/models/MonitoredTrip.java 60.71% <53.84%> (+5.15%) 28.00 <7.00> (+10.00)
...iddleware/tripMonitor/jobs/CheckMonitoredTrip.java 41.76% <55.20%> (+16.59%) 19.00 <16.00> (+9.00)
...nner/middleware/controllers/api/LogController.java 46.29% <66.66%> (ø) 2.00 <0.00> (ø)
... and 14 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6971187...c9499cc. Read the comment docs.

@br648
Copy link
Contributor

br648 commented Sep 16, 2020

@evansiroky the unit test "canMonitorTrip()" fails with the following exception:

java.io.FileNotFoundException: src\test\resources\org\opentripplanner\middleware\planResponse.json (The system cannot find the file specified)

This file is located in src\test\resources\org\opentripplanner\middleware\persistence.

Copy link
Contributor

@br648 br648 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the face of it this looks really good. I don't feel I have enough experience to comment on the finer workings so will leave that to others. Perhaps a walk through would be useful, at least for me?

Copy link
Collaborator

@binh-dam-ibigroup binh-dam-ibigroup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will need to play some more with it, but see my comments so far.

@@ -279,5 +302,68 @@ public boolean delete() {
// TODO: Add journey state deletion.
return Persistence.monitoredTrips.removeById(this.id);
}

public List<NameValuePair> getParsedParams() throws URISyntaxException {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should return a Map, and it would simplify method isArriveBy below and the class constructor.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the be a @BsonIgnore annotation?

Copy link
Collaborator

@binh-dam-ibigroup binh-dam-ibigroup Sep 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been trying to see if the stuff plays well with the UI. This is what I understand is happening:

  • @BsonIgnore seems to prevent reflection on the field/method on serialization, but reflection on the underlying types is still attempted on deserialization.
  • @JsonIgnore seems to prevent reflection both on serialization and on deserialization. This is what we should use.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind that didn't seem to work. So this method should probably be renamed, e.g. parseParams()

// parse query params
List<NameValuePair> params = URLEncodedUtils.parse(
new URI(String.format("http://example.com/%s", trip.queryParams)),
UTF_8
);

// begin building a new list and along the way and figure out if this trip is a depart at or arrive by trip
// building a new list by copying all values, except for the date which is set to the target date
List<NameValuePair> newParams = new ArrayList<>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Echoing my comment for MonitoredTrip#getParsedParams, a map might be useful here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree because this variable is sent to the URLEncodedUtils.format which needs some kind of Iterable.

List<NameValuePair> parsedParams = getParsedParams();
for (NameValuePair parsedParam : parsedParams) {
if (parsedParam.getName().equals("time")) {
tripTime = parsedParam.getValue();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least of these things should also take place with this change:

  • Update all MonitoredTrip records in Mongo with a value for tripTime (and on UI side, make sure that field gets populated too),
  • If reading a MonitoredTrip record from Mongo with no tripTime value set, initialize tripTime on first use of getHour() or getMinute(), which would be more fool-proof.

* use the local time at the destination. Therefore, this method will return the timezone at the destination if this
* trip is an arriveBy trip, or the timezone at the origin if the trip is a depart at trip.
*/
@BsonIgnore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. @BsonIgnore and JsonIgnore are... ignored by the Mongo POJO codec on serialization. The easiest way is to rename the method (findTimezoneForTargetLocation?). If a get prefix is still needed, we can use the transient keyword (we've faced a similar issue here)

Copy link
Collaborator

@binh-dam-ibigroup binh-dam-ibigroup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Some MonitoredTrip methods need to be modified to play well with serialization.
  • MonitoredTrip#tripTime may need to be initialized on first use, or the databases need to be updated, let me know what approach you'd prefer.

@evansiroky
Copy link
Contributor Author

Should be ready for review again.

Copy link
Collaborator

@binh-dam-ibigroup binh-dam-ibigroup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, there is one gap regarding the initialization of tripTime I would like to get resolved.

// extract trip time from parsed params
Map<String, String> params = parseQueryParams();
tripTime = params.get("time");
if (tripTime == null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To follow up on #75 (comment),
the UI does not currently initialize tripTime, so tripTime also needs to be initialized when polling tripTimeHour or tripTimeMinute. (Those methods are called by CheckMonitoredTrip#shouldSkipMonitoredTripCheck).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok I see what's happening. I added some logic to the MonitoredTripController's preCreateHook and preUpdateHook to enforce the existence of the trip time before it gets saved to the database.

*/
@BsonIgnore
public int tripTimeHour() {
return Integer.valueOf(tripTime.split(":")[0]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should still be a null check (at least) here and in tripTimeMinutes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tripTime should be guaranteed to exist due to #75 (comment).

@@ -24,7 +24,7 @@
import static com.beerboy.ss.descriptor.EndpointDescriptor.endpointPath;
import static com.beerboy.ss.descriptor.MethodDescriptor.path;
import static org.opentripplanner.middleware.auth.Auth0Connection.isUserAdmin;
import static org.opentripplanner.middleware.utils.DateTimeUtils.YYYY_MM_DD;
import static org.opentripplanner.middleware.utils.DateTimeUtils.DEFAULT_DATE_FORMAT_PATTERN;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my view, this variable just became harder to read with this name change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree and believe it has resulted in a more explicit meaning with intended usage conveyed through its name.

public boolean isArriveBy() throws URISyntaxException {
// if arriveBy is not included in query params, OTP will default to false, so initialize to false
return parseQueryParams().getOrDefault("arriveBy", "false").equals("true");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the code in parseQueryParams and isArriveBy to be a little hard to read and overly clever. I would prefer the use of one or two variables to improve legibility. Also, these could use some basic javadoc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also agree that the parseQueryParams is clever, but don't think it's too clever. I think breaking it up wouldn't really add much value. I went ahead and added JavaDoc though in 6fd00a9

* - the current time is after the lead time before the next itinerary starts, but is over an hour until the
* itinerary start time and the trip has already been checked within the last 60 minutes
* - the current time is after the lead time before the next itinerary starts and between 60-15 minutes prior to the
* itinerary start time, but a check has occurred within the last 15 minutes
Copy link
Contributor

@landonreed landonreed Oct 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit wordy. The language could be simplified to improve how it reads (without losing clarity). Also, I don't think this accounts for the every minute check within 30 minutes that has been added.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this a little bit in 6fd00a9, but prefer to be hyper-specific when talking about timing matters.

Copy link
Contributor

@landonreed landonreed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good, but I do have some concerns about how some of the CheckMonitoredTrips methods have been structured and how they update class variables (could use some touch ups to comments as well).

@landonreed landonreed assigned evansiroky and unassigned landonreed Oct 8, 2020
@evansiroky evansiroky assigned landonreed and unassigned evansiroky Oct 9, 2020
@codecov-io
Copy link

Codecov Report

Merging #75 into dev will increase coverage by 3.39%.
The diff coverage is 54.43%.

Impacted file tree graph

@@             Coverage Diff              @@
##                dev      #75      +/-   ##
============================================
+ Coverage     38.74%   42.13%   +3.39%     
- Complexity      264      296      +32     
============================================
  Files            81       81              
  Lines          2261     2302      +41     
  Branches        258      265       +7     
============================================
+ Hits            876      970      +94     
+ Misses         1301     1228      -73     
- Partials         84      104      +20     
Impacted Files Coverage Δ Complexity Δ
...nner/middleware/controllers/api/ApiController.java 34.45% <0.00%> (ø) 4.00 <0.00> (ø)
...eware/controllers/api/MonitoredTripController.java 19.04% <0.00%> (-9.53%) 2.00 <0.00> (ø)
...iddleware/controllers/api/OtpRequestProcessor.java 21.27% <0.00%> (ø) 3.00 <0.00> (ø)
...tripplanner/middleware/otp/response/Itinerary.java 77.41% <0.00%> (+8.66%) 7.00 <0.00> (+2.00)
...g/opentripplanner/middleware/otp/response/Leg.java 55.17% <0.00%> (+5.17%) 5.00 <0.00> (+1.00)
...anner/middleware/persistence/TypedPersistence.java 47.82% <0.00%> (ø) 14.00 <0.00> (ø)
.../opentripplanner/middleware/otp/OtpDispatcher.java 79.31% <33.33%> (+68.59%) 4.00 <0.00> (+3.00)
...iddleware/tripMonitor/jobs/CheckMonitoredTrip.java 41.71% <54.90%> (+16.54%) 19.00 <16.00> (+9.00)
...pentripplanner/middleware/utils/DateTimeUtils.java 63.04% <60.00%> (+11.88%) 12.00 <2.00> (+2.00)
...nner/middleware/controllers/api/LogController.java 46.29% <66.66%> (ø) 2.00 <0.00> (ø)
... and 14 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6971187...02379c1. Read the comment docs.

Copy link
Contributor

@landonreed landonreed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes/consideration.

@landonreed landonreed merged commit 4d664d2 into dev Oct 14, 2020
@landonreed landonreed deleted the trip-monitor-timing branch October 14, 2020 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants