-
Notifications
You must be signed in to change notification settings - Fork 26
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
[scheduler] Add core logic to accomodate monthly tasks limit #1756
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Predicate.EQ("namespace", namespace), | ||
Predicate.EQ("type", taskType), | ||
Predicate.GE("startTime", startOfMonthTimestamp), | ||
Predicate.LE("startTime", endOfMonthTimestamp) |
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.
Predicate.LE("startTime", endOfMonthTimestamp)
looks incorrect, was it endTime ?
btw do we really need this ?
my understanding is
Predicate.GE("startTime", startOfMonthTimestamp)
is enough
we don't create tasks in the future
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, I think we should use creation time created
not startTime
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.
thanks. changed to just createdTime > first day of month
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
@@ -97,43 +119,99 @@ public void shutdown() throws SchedulerException { | |||
} | |||
|
|||
private void updateSchedules() throws SchedulerException { | |||
|
|||
final Supplier<HashMap<String, Boolean>> namespaceToQuotaExceededMap = scheduledRefreshSupplier( |
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 needs to be created as a field once, here it is created at every updateSchedules
call
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.
let's call it cachedNamespaceToQuotaExceeded
not a fan of suffixing the type of the object ("Map") in Java, Java is statically typed and IDE can easily tell what's the type.
also xToY
is pretty standard for a Map.
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 when returning cache map, it may be a good practice to ensure this map is immutable
else a cache consumer could edit it.
we could do
scheduledRefreshSupplier(() -> Map.copyOf(getNamespaceToQuotaExceededMap()))
but see my comment below
I think we could just have getNamespaceToQuotaExceededMap return an ImmutableMap
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.
done
} | ||
} catch (final Exception e) { | ||
log.error("Error removing job key {}", jobKey, e); | ||
} | ||
} | ||
} | ||
|
||
private void schedule(final E entity) { | ||
private HashMap<String, Boolean> getNamespaceToQuotaExceededMap() { |
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.
let's use Map
for the interface
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.
done
} | ||
} catch (final Exception e) { | ||
log.error("Error removing job key {}", jobKey, e); | ||
} | ||
} | ||
} | ||
|
||
private void schedule(final E entity) { | ||
private HashMap<String, Boolean> getNamespaceToQuotaExceededMap() { | ||
HashMap<String, Boolean> m = new HashMap<>(); |
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.
maybe we want to return an Immutable Map.
Can be done with
- guava ImmutableMap
- using a stream
- using Map.copyOf()
see my comment above
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.
done using Map.copyOf()
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
...e-scheduler/src/main/java/ai/startree/thirdeye/scheduler/ThirdEyeSchedulerConfiguration.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
thirdeye-scheduler/src/main/java/ai/startree/thirdeye/scheduler/TaskCronSchedulerRunnable.java
Outdated
Show resolved
Hide resolved
@@ -103,37 +128,92 @@ private void updateSchedules() throws SchedulerException { | |||
// also only fetch only active entities directly and remove is active from Schedulable interface | |||
final List<E> allEntities = entityDao.findAll(); | |||
|
|||
final HashMap<String, Boolean> |
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.
As soon i change every type from HashMap<String, Boolean> to Map<String, Boolean>
and make getNamespaceToQuotaExceededMap() return an immutable map
namespaceToQuotaExceededSupplier.get() keeps returning null map
not sure if i'm missing something totally basic?
@cyrilou242
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.
nvm, fixed it
it was because null key was causing issue in immutable map, resulting into NPE when calling Map.copyOf()
but hashmap handles null string key well
final Map<Long, E> idToEntity = allEntities.stream() | ||
.collect(Collectors.toMap(AbstractDTO::getId, e -> e)); | ||
final Set<JobKey> scheduledJobKeys = scheduler.getJobKeys(groupMatcher); | ||
for (final JobKey jobKey : scheduledJobKeys) { | ||
try { | ||
final Long id = getIdFromJobKey(jobKey); | ||
final E entity = idToEntity.get(id); | ||
final String entityNamespace = nonNullNamespace(entity.namespace()); |
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.
will throw an NPE if entity is null
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.
see null check below
@@ -42,7 +57,9 @@ | |||
import org.slf4j.LoggerFactory; | |||
|
|||
public class TaskCronSchedulerRunnable<E extends AbstractDTO> implements Runnable { | |||
|
|||
|
|||
private static final String NULL_NAMESPACE_KEY = "__null__"; |
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.
nit:
See how it's implemented here:
thirdeye/thirdeye-server/src/main/java/ai/startree/thirdeye/auth/AuthorizationManager.java
Line 107 in a901ec5
private static final String NULL_NAMESPACE_KEY = "__NULL_NAMESPACE_" + RandomStringUtils.randomAlphanumeric(10).toUpperCase(); |
in case someone decides to use __null__
as a namespace name.
so I prefer to user a key with a random 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.
ahh, i see. yes, this should be handled. on it!
Issue(s)
thirdeye tasks limit per month
Description
ThirdEye Free Tier Usage Quota
#1751 introduced TaskQuotasConfiguration as part of workspace configuration
This PR adds the core logic to incorporate task quotas in the job scheduler for both DETECTION and NOTIFICATION tasks
It computes, for each workspace, if it has exceeded the DETECTION/NOTIFICATION monthly task quota
If yes, then it stops the currently running jobs and does not let any new job get scheduled
Testing
e2e tests are out of scope, will be done in another PR.
Manually tested locally with following data
Related server.yaml config:
Tasks Count for Current Month:
As per the above data, namespace 1 has exceeded DETECTION tasks quota
and namespace1 and namespace3 have exceeded NOTIFICATION tasks quota
Scheduler should not schedule & should cleanup any tasks for such cases
Scheduler activity in Server log:
server-logs-with-quota.txt
Reset the task quotas to null by removing namespaceQuotasConfiguration from server.yaml and using
/api/workspace-configuration/reset
All jobs should be scheduled for all namespaces
without any detection/notification task quota check
Scheduler activity in Server log:
server-logs-without-quota.txt