-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
App Configuration: recurring time window filter #40093
base: feature/spring-boot-3
Are you sure you want to change the base?
App Configuration: recurring time window filter #40093
Conversation
… to time window settings
API change check APIView has identified API level changes in this PR and created following API reviews. |
...pring/cloud/feature/management/implementation/timewindow/recurrence/RecurrenceValidator.java
Outdated
Show resolved
Hide resolved
...pring/cloud/feature/management/implementation/timewindow/recurrence/RecurrenceValidator.java
Outdated
Show resolved
Hide resolved
...pring/cloud/feature/management/implementation/timewindow/recurrence/RecurrenceValidator.java
Outdated
Show resolved
Hide resolved
...pring/cloud/feature/management/implementation/timewindow/recurrence/RecurrenceValidator.java
Outdated
Show resolved
Hide resolved
...pring/cloud/feature/management/implementation/timewindow/recurrence/RecurrenceValidator.java
Outdated
Show resolved
Hide resolved
|
||
- Parameters | ||
|
||
| Property | Relevance | Description | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mrm9084 I merged all parameters to one table. It's clear that we support these 2 types for recurrence patter. But the shortcoming is that I need to declare the supported and unsupported types for each property.
Please let me know if you have any ideas about how to make it better.
|
||
if (!StringUtils.hasText(start) && !StringUtils.hasText(end)) { | ||
if (settings.getStart() == null && settings.getEnd() == null) { | ||
LOGGER.warn("The {} feature filter is not valid for feature {}. It must specify either {}, {}, or both.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mrm9084 Shall we throw exception here?
In the validations of recurrence, I just throw exception, because if there're invalid value for the enum type, it's easier to throw exception. Maybe we need to keep consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I would double check with DotNet, but I think we decided most "invalid" cases result in logs and disabled features.
A similar thing happens with requesting a feature flag that doesn't exist, you just get false
returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we may have had a design change where we now throw more errors than just fail. We need to be careful that we don't make a previous valid setup/non error setup to throw an error as that would be a breaking change.
|
||
| Property | Relevance | Description | | ||
|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| **type** | Required | Two valid values: `Daily`, `Weekly`. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this type
can be optional, because we have a default value as Daily
.
My concern is that if I announce all parameters to be optional, then maybe users will not define any parameters in recurrence pattern like the following.
start: "Mon, 13 May 2024 02:00:00 GMT",
end: "Mon, 13 May 2024 03:00:00 GMT",
recurrence:
range:
type: "NoEnd"
Shall we support this? Or throw invalid exception since there's no pattern
parameter? @mrm9084
/** | ||
* @param numberOfOccurrences the repeat times to be set | ||
* */ | ||
public void setNumberOfOccurrences(int numberOfOccurrences) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is different from the setInterval(interger interval)
/** | ||
* @param interval the time units to be set | ||
* */ | ||
public void setInterval(Integer interval) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You use int
type in public void setNumberOfOccurrences(int numberOfOccurrences)
Is there any reason use Integer
here? It doesn't make sense to do null check here, since Interval
has default value 1
.
|
||
// Check whether "Start" is a valid first occurrence | ||
final RecurrencePattern pattern = settings.getRecurrence().getPattern(); | ||
if (pattern.getDaysOfWeek().stream().noneMatch((dayOfWeekStr) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be dayOfWeek instead of dayOfWeekStr? getDaysOfWeek returns List
numberOfOccurrences: 3 | ||
``` | ||
|
||
The `recurrence` settings is made up of two parts: `pattern` (how often the time window will repeat) and `range` (for how long the recurrence pattern will repeat). To create a recurrence rule, you must specify both `pattern` and `range`. Any pattern type can work with any range type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be 3/4 parts as the start/end are required and give the period of time that the flag is enabled for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we should mention start/end here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use "2 parts" because there's only 2 parameters behind the "recurrence" parameter.
I agree that we should mention start/end here.
Updated to the following description.
To create a recurrence rule, you need to specify 3 parts: `start`, `end` and `recurrence`.
The `start` and `end` parameters define the time window which need to recur periodically.
The `recurrence` parameter is made up of two parts: `pattern` (how often the time window will repeat) and `range` (for how long the recurrence pattern will repeat). To create a recurrence rule, you must specify both `pattern` and `range`. Any pattern type can work with any range type.
|
||
#### Recurrence Pattern | ||
|
||
There are two possible recurrence pattern types: `Daily` and `Weekly`. For example, a time window could repeat "every day", "every 3 days", "every Monday" or "every other Friday". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this does a good job explaining Daily
/Weekly
. It also doesn't help that a single period may not be over 24 hours but can take place over 2 days.
Daily is the Days that have passed, which isn't actually Daily. Same with Weekly. Either that or I misunderstand how this works, which is also an issue.
You should separate the Daily and Weekly examples from each other so you know which one a person may want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to the following
There are two possible recurrence pattern types: `Daily` and `Weekly`.
`Daily` causes an event to repeat based on a number of days between each occurrence. For example, "every day" or "every 3 days".
`Weekly` causes an event to repeat on the same day or days of the week, based on the number of weeks between each set of occurrences. For example, "every Monday" or "every other Friday".
interval: 2, | ||
daysOfWeek: | ||
- Monday | ||
- Tuesday |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried using this yaml. I get a json parsing error when trying to use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, updated
/** | ||
* A recurrence definition describing how time window recurs | ||
* */ | ||
public class Recurrence { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add the Annotation to all of the models to ignore unknown fields. It will save us at some point if a field is added to the portal by default. Wouldn't be the first time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
/** | ||
* The date to stop applying the recurrence pattern | ||
* */ | ||
private ZonedDateTime endDate = Instant.ofEpochMilli(Integer.MAX_VALUE).atZone(ZoneOffset.UTC); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the intent of this? Is it just an unrealistic end date to cause errors? Also, why not just 0 instead of max int? The number of milliseconds of a max int is just a few days. So instead of 01-01-1970 it's 01-25-1970?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this default value.
Property | Relevance | Description | | ||
-----------|---------------|------------- | ||
**type** | Required | Three valid values: `NoEnd`, `EndDate` and `Numbered`. | ||
**endDate** | Optional | Specifies the date time to stop applying the pattern. Note that as long as the start time of the last occurrence falls before the end date, the end time of that occurrence is allowed to extend beyond it. <br /> It's required for `EndDate` type, not applicable for `NoEnd` and `Numbered` type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
endDate currently has a default value. It's not "required", The end date just has to be before 1970-01-25T20:31:23.647Z
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the default value of endDate
. It sounds not reasonable that we have some default value.
/** | ||
* The number of times to repeat the time window | ||
*/ | ||
private int numberOfOccurrences = Integer.MAX_VALUE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't have a default value if it's a required field. Right now the default value makes it effectively a no end filter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I agree that no need to set a default value.
Co-authored-by: Matthew Metcalf <[email protected]>
Co-authored-by: Matthew Metcalf <[email protected]>
…/com/azure/spring/cloud/feature/management/filters/TimeWindowFilter.java Co-authored-by: Matthew Metcalf <[email protected]>
…m/ivywei0125/azure-sdk-for-java into yuwe/recurring-time-window-filter
|
||
**Note:** `start` must be a valid first occurrence which fits the recurrence pattern. For example, if we define to repeat on every other Monday and Tuesday, then the start time should be in Monday or Tuesday. <br /> Additionally, the duration of the time window cannot be longer than how frequently it occurs. For example, it is invalid to have a 25-hour time window recur every day. | ||
|
||
#### Recurrence Range |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tested this? I have no exception is thrown for me when I make one with it.
|
||
if (!StringUtils.hasText(start) && !StringUtils.hasText(end)) { | ||
if (settings.getStart() == null && settings.getEnd() == null) { | ||
LOGGER.warn("The {} feature filter is not valid for feature {}. It must specify either {}, {}, or both.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we may have had a design change where we now throw more errors than just fail. We need to be careful that we don't make a previous valid setup/non error setup to throw an error as that would be a breaking change.
…ead of catching the exception
Add "Recurrence" parameter for TimeWindowFilter using Outlook-style schema:
https://learn.microsoft.com/en-us/graph/outlook-schedule-recurring-events#using-patterns-and-ranges-to-create-recurring-events
Example:
The main logic of how to check whether current time is within any recurring time window:
Find the previous occurrence of the recurring time window, let's call it prevOccurrenceStart
Check whether the current time: time is within the time window: prevOccurrenceStart ~ prevOccurrenceStart + End - Start