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

feat: Add Schedule API #937

Merged
merged 11 commits into from
Nov 7, 2022
Merged

feat: Add Schedule API #937

merged 11 commits into from
Nov 7, 2022

Conversation

mjameswh
Copy link
Contributor

What was changed

  • Add Schedule API

Why?

  • Add Schedule API

Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

Overall LGTM.
All of these new APIs need to be marked experimental.
I reviewed this very late at night so I may have missed things or asked trivial questions.

}

interface ScheduleClientCallsInterceptorFactoryInput {
scheduleId: string;
Copy link
Member

Choose a reason for hiding this comment

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

Are we instantiating these interceptors per schedule instance? I wouldn’t do that, the interceptors shouldn’t be bound to a schedule.

Copy link
Member

Choose a reason for hiding this comment

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

We should have probably avoided that for the client interceptors too.
Let’s think about this. I see that you did this for consistency.

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 agree.

In that case, I don't think we need interceptor factories, do we?

If we can avoid these, then we can safely deprecate the previous approach in workflow client by defining:

export interface WorkflowClientInterceptors {
  calls?: (WorkflowClientCallsInterceptorFactory|WorkflowClientCallsInterceptor)[];
}

and then type checking either calls items are typeof object (new way) or function (deprecated way). We will have to continue supporting the previous approach for some minor versions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regarding Schedule interceptors, I will immediately remove factory and make

export interface ScheduleClientInterceptors {
  calls?: ScheduleClientCallsInterceptor[];
}

Makes sense?

Copy link
Member

Choose a reason for hiding this comment

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

Probably get rid of the calls attribute and flatten it out:

export interface WorkflowClientInterceptor {
  // ... rename from WorkflowClientCallsInterceptor
}

// Maintain the export alias
export type WorkflowClientCallsInterceptor = WorkflowClientInterceptor;

export interface WorkflowClientInterceptors = {
  /** @deprecated */
  calls?: WorkflowClientCallsInterceptorFactory[];
}

interface ScheduleClientInterceptor {
}

export interface ClientInterceptors {
  workflow?: WorkflowClientInterceptors | WorkflowClientInterceptor[];
  schedule?: ScheduleClientInterceptor[];
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pretty much what I had in mind. I'll do the WorkflowClient refactor in a distinct PR though.

*
* @default undefined (unlimited)
*/
remainingActions?: number;
Copy link
Member

Choose a reason for hiding this comment

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

In the protos, ScheduleInfo is the stuff that can't be updated. It is not part of Schedule, which is everything that can be updated (everything else). ScheduleState is part of Schedule and can be updated. It's essentially the things that are expected to change and might change without an explicit update, as opposed to SchedulePolicies, which are not expected to change (but can be changed by the user).

I think at least using the same terms will help everyone avoid getting confused

firstExecutionRunId: string;
}

export interface ScheduleAction {
Copy link
Member

Choose a reason for hiding this comment

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

I understand that we might want to tweak some names at this level, but it does seem confusing to have a ScheduleAction that corresponds to a ScheduleActionResult in the proto, while ScheduleAction in the proto is something else

Copy link
Contributor Author

@mjameswh mjameswh Nov 2, 2022

Choose a reason for hiding this comment

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

Definitely agreed. That name is also confusing in regard to other types in the TypeScript's schedule API.

I'm considering this:

export interface ScheduleExecutionResult {
  /** Time that the Action was scheduled for, including jitter */
  scheduledAt: Date;

  /** Time that the Action was actually taken */
  takenAt: Date;

  /** The Action that was taken */
  action: ScheduleExecutionActionResult;
}

export type ScheduleExecutionActionResult = ScheduleExecutionStartWorkflowActionResult;

export interface ScheduleExecutionStartWorkflowActionResult {
  type: 'startWorkflow';
  workflow: WorkflowExecutionWithFirstExecutionRunId;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

This API hides all protos, right? So I don't see the issue with name conflicts. And generally prefer shorter terms, like:

export interface ScheduleAction {
  /** Time that the Action was scheduled for, including jitter */
  scheduledAt: Date;

  /** Time that the Action was actually taken */
  takenAt: Date;

  /** The result of the Action that was taken */
  result: ScheduleActionResult;
}

export type ScheduleActionResult = StartWorkflowActionResult;

export interface StartWorkflowActionResult {
  type: 'startWorkflow';
  workflow: WorkflowExecutionWithFirstExecutionRunId;
}

Copy link
Contributor Author

@mjameswh mjameswh Nov 4, 2022

Choose a reason for hiding this comment

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

@lorensr I obviously prefer shorter names.

The problem here is that Describe, List, Create/Update, CompiledCreate/CompiledUpdate, recentActions, and runningActions all have distinct variants of the ScheduleAction* types. At this moment, we could deal with this by Omit<>ing or Pick<>ing some fields, but that would not work once we add other types of actions.

Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

This looks great, I don't have a lot of comments at this point and I would merge soon.
I'd follow up with a cleanup PR that adds an internal base class to all of the different SDK clients.

/**
* When Actions should be taken
*/
spec: RequireAtLeastOne<ScheduleSpec, 'calendars' | 'intervals' | 'cronExpressions'>;
Copy link
Member

Choose a reason for hiding this comment

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

I think I saw a comment by David saying that we don't require at least one of these on the server side.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right, but the schedule is then a no-op. Seems like a reasonable DX addition...

*
* @experimental
*/
export enum ScheduleOverlapPolicy {
Copy link
Member

Choose a reason for hiding this comment

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

Still not liking the inconsistency here with the rest of the SDK.
I'm not blocking on this but it deserves a short discussion IMHO.

Copy link
Contributor

Choose a reason for hiding this comment

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

Here's the proposal discussion: temporalio/proposals#62 (comment)

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 only thing that bothers me with reexporting the proto's enum directly is that it doesn't provide type doc. The values in this enum are not trivial to understand for users, so that doc is particularly important.

@mjameswh mjameswh changed the title feat: Add Schedule API [DRAFT] feat: Add Schedule API Nov 7, 2022
@mjameswh mjameswh marked this pull request as ready for review November 7, 2022 18:28
- Moved 'WorkflowStartOptions' to a different file to avoid dependency cycle
- Add 'Long' in client (required for proto encoding)
- Remove 'ms' in client
- Expose schedule API
@mjameswh mjameswh merged commit 808e562 into temporalio:main Nov 7, 2022
@mjameswh mjameswh deleted the schedule-api branch November 17, 2022 17:23
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.

5 participants