Skip to content

Commit

Permalink
enable strict on durable module
Browse files Browse the repository at this point in the history
  • Loading branch information
balanza committed Apr 13, 2021
1 parent 45c6655 commit 0d28679
Show file tree
Hide file tree
Showing 15 changed files with 69 additions and 95 deletions.
6 changes: 1 addition & 5 deletions HandleNHCreateOrUpdateInstallationCallActivity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import {
getActivityBody
} from "./handler";

export {
ActivityBodyImpl,
ActivityInput,
ActivityResultSuccess
} from "./handler";
export { ActivityInput, ActivityResultSuccess } from "./handler";
export const activityName = "HandleNHCreateOrUpdateInstallationCallActivity";

const activityFunctionHandler = createActivity(
Expand Down
4 changes: 2 additions & 2 deletions HandleNHCreateOrUpdateInstallationCallOrchestrator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as t from "io-ts";
import * as o from "../utils/durable/orchestrators";

import { CreateOrUpdateInstallationMessage } from "../generated/notifications/CreateOrUpdateInstallationMessage";
import { ActivityBodyImpl as CreateOrUpdateActivityBodyImpl } from "../HandleNHCreateOrUpdateInstallationCallActivity";
import { ActivityInput as CreateOrUpdateActivityInput } from "../HandleNHCreateOrUpdateInstallationCallActivity";
import { NotificationHubConfig } from "../utils/notificationhubServicePartition";

export const OrchestratorName =
Expand All @@ -21,7 +21,7 @@ export type NhCreateOrUpdateInstallationOrchestratorCallInput = t.TypeOf<
>;

interface IHandlerParams {
createOrUpdateActivity: o.CallableActivity<CreateOrUpdateActivityBodyImpl>;
createOrUpdateActivity: o.CallableActivity<CreateOrUpdateActivityInput>;
notificationHubConfig: NotificationHubConfig;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getConfigOrThrow } from "../utils/config";
import { getHandler } from "./handler";

import {
ActivityBodyImpl as CreateOrUpdateActivityBodyImpl,
ActivityInput as CreateOrUpdateActivityBodyImpl,
activityName as CreateOrUpdateActivityName,
ActivityResultSuccess as CreateOrUpdateActivityResultSuccess
} from "../HandleNHCreateOrUpdateInstallationCallActivity";
Expand Down
7 changes: 4 additions & 3 deletions HandleNHDeleteInstallationCallActivity/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ export const ActivityInput = t.interface({
// Activity Result
export { ActivityResultSuccess } from "../utils/durable/activities";

export type ActivityBodyImpl = ActivityBody<ActivityInput>;

/**
* For each Notification Hub Message of type "Delete" calls related Notification Hub service
*/

export const getActivityBody = (
buildNHService: (nhConfig: NotificationHubConfig) => NotificationHubService
): ActivityBodyImpl => ({ input, logger }) => {
): ActivityBody<ActivityInput, ActivityResultSuccess> => ({
input,
logger
}) => {
logger.info(`INSTALLATION_ID=${input.installationId}`);
const nhService = buildNHService(input.notificationHubConfig);

Expand Down
9 changes: 2 additions & 7 deletions HandleNHDeleteInstallationCallActivity/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import { createActivity } from "../utils/durable/activities";
import { buildNHService } from "../utils/notificationhubServicePartition";
import {
ActivityBodyImpl,
ActivityInput,
ActivityResultSuccess,
getActivityBody
} from "./handler";

export {
ActivityBodyImpl,
ActivityInput,
ActivityResultSuccess
} from "./handler";
export { ActivityInput, ActivityResultSuccess } from "./handler";
export const activityName = "HandleNHDeleteInstallationCallActivity";

const activityFunctionHandler = createActivity<ActivityBodyImpl>(
const activityFunctionHandler = createActivity<ActivityInput>(
activityName,
ActivityInput,
ActivityResultSuccess,
Expand Down
4 changes: 2 additions & 2 deletions HandleNHDeleteInstallationCallOrchestrator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as t from "io-ts";

import { DeleteInstallationMessage } from "../generated/notifications/DeleteInstallationMessage";

import { ActivityBodyImpl as DeleteInstallationActivityBodyImpl } from "../HandleNHDeleteInstallationCallActivity";
import { ActivityInput as DeleteInstallationActivityInput } from "../HandleNHDeleteInstallationCallActivity";

import * as o from "../utils/durable/orchestrators";
import { NotificationHubConfig } from "../utils/notificationhubServicePartition";
Expand All @@ -23,7 +23,7 @@ export const OrchestratorCallInput = t.interface({

interface IHandlerParams {
deleteInstallationActivity: o.CallableActivity<
DeleteInstallationActivityBodyImpl
DeleteInstallationActivityInput
>;
legacyNotificationHubConfig: NotificationHubConfig;
}
Expand Down
4 changes: 2 additions & 2 deletions HandleNHDeleteInstallationCallOrchestrator/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as df from "durable-functions";
import {
ActivityBodyImpl as DeleteInstallationActivityBodyImpl,
ActivityInput as DeleteInstallationActivityInput,
activityName as DeleteInstallationActivityName,
ActivityResultSuccess as DeleteInstallationActivityResultSuccess
} from "../HandleNHDeleteInstallationCallActivity";
Expand All @@ -12,7 +12,7 @@ import { getHandler } from "./handler";
const config = getConfigOrThrow();

const deleteInstallationActivity = o.callableActivity<
DeleteInstallationActivityBodyImpl
DeleteInstallationActivityInput
>(DeleteInstallationActivityName, DeleteInstallationActivityResultSuccess, {
...new df.RetryOptions(5000, config.RETRY_ATTEMPT_NUMBER),
backoffCoefficient: 1.5
Expand Down
6 changes: 0 additions & 6 deletions HandleNHNotificationCallActivity/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ export type HandleNHNotificationCallActivityInput = t.TypeOf<
typeof HandleNHNotificationCallActivityInput
>;

// tslint:disable:no-any
const createUnexpecterError = (x: any): Error =>
new Error(`Unexpected object: ${toString(x)}`);

/**
* For each Notification Hub Message calls related Notification Hub service
*/
Expand Down Expand Up @@ -104,8 +100,6 @@ export const getCallNHServiceActivityHandler = (
return failActivity(logger)(e.message);
}
);
default:
throw createUnexpecterError(message);
}
})
.fold<ActivityResult>(identity, success)
Expand Down
11 changes: 4 additions & 7 deletions HandleNHNotifyMessageCallActivity/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,17 @@ export type ActivityInput = t.TypeOf<typeof ActivityInput>;
// Activity Result
export { ActivityResultSuccess } from "../utils/durable/activities";

// ActivityBody
export type ActivityBodyImpl = ActivityBody<
ActivityInput,
ActivityResultSuccess
>;

/**
* For each Notification Hub Message of type "Delete" calls related Notification Hub service
*/

export const getActivityBody = (
telemetryClient: TelemetryClient,
buildNHService: (nhConfig: NotificationHubConfig) => NotificationHubService
): ActivityBodyImpl => ({ input, logger }) => {
): ActivityBody<ActivityInput, ActivityResultSuccess> => ({
input,
logger
}) => {
logger.info(`INSTALLATION_ID=${input.message.installationId}`);
const nhService = buildNHService(input.notificationHubConfig);
return notify(nhService, input.message.installationId, input.message.payload)
Expand Down
6 changes: 1 addition & 5 deletions HandleNHNotifyMessageCallActivity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ import {
getActivityBody
} from "./handler";

export {
ActivityBodyImpl,
ActivityInput,
ActivityResultSuccess
} from "./handler";
export { ActivityInput, ActivityResultSuccess } from "./handler";
export const activityName = "HandleNHNotifyMessageCallActivity";

const config = getConfigOrThrow();
Expand Down
10 changes: 8 additions & 2 deletions HandleNHNotifyMessageCallOrchestrator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import * as t from "io-ts";

import { Task } from "durable-functions/lib/src/classes";

import { ActivityBodyImpl as NotifyMessageActivityBodyImpl } from "../HandleNHNotifyMessageCallActivity";
import {
ActivityInput as NotifyMessageActivityInput,
ActivityResultSuccess as NotifyMessageActivityResultSuccess
} from "../HandleNHNotifyMessageCallActivity";

import { NotifyMessage } from "../generated/notifications/NotifyMessage";

Expand All @@ -29,7 +32,10 @@ export type NhNotifyMessageOrchestratorCallInput = t.TypeOf<
>;

interface IHandlerParams {
notifyMessageActivity: CallableActivity<NotifyMessageActivityBodyImpl>;
notifyMessageActivity: CallableActivity<
NotifyMessageActivityInput,
NotifyMessageActivityResultSuccess
>;
legacyNotificationHubConfig: NotificationHubConfig;
}

Expand Down
4 changes: 2 additions & 2 deletions HandleNHNotifyMessageCallOrchestrator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { getNHLegacyConfig } from "../utils/notificationhubServicePartition";
import { getHandler } from "./handler";

import {
ActivityBodyImpl as NotifyMessageActivityBodyImpl,
ActivityInput as NotifyMessageActivityInput,
activityName as NotifyMessageActivityName,
ActivityResultSuccess as NotifyMessageActivityResultSuccess
} from "../HandleNHNotifyMessageCallActivity";

const config = getConfigOrThrow();
const legacyNotificationHubConfig = getNHLegacyConfig(config);

const notifyMessageActivity = callableActivity<NotifyMessageActivityBodyImpl>(
const notifyMessageActivity = callableActivity<NotifyMessageActivityInput>(
NotifyMessageActivityName,
NotifyMessageActivityResultSuccess,
{
Expand Down
44 changes: 15 additions & 29 deletions utils/durable/activities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export { createLogger } from "./log";
export * from "./returnTypes";

export type ActivityBody<
Input,
Input = unknown,
Success extends ActivityResultSuccess = ActivityResultSuccess,
Failure extends ActivityResultFailure = ActivityResultFailure
// Bindings extends Array<unknown> = []
Expand All @@ -25,26 +25,6 @@ export type ActivityBody<
// bindings?: Bindings;
}) => TaskEither<Failure, Success>;

// extract the input type from an ActivityBody type
export type InputOfActivityBody<B extends ActivityBody<unknown>> = B extends (
p: infer P
) => TaskEither<infer _, infer __>
? P extends { context: Context; input: infer I }
? I
: never
: never;

// extract the success type from an ActivityBody type
export type SuccessOfActivityBody<B extends ActivityBody<unknown>> = B extends (
p: infer P
) => TaskEither<infer _, infer S>
? P extends { context: Context; input: infer __ }
? S extends ActivityResultSuccess
? S
: never
: never
: never;

/**
* Wraps an activity execution so that types are enforced and errors are handled consistently.
* The purpose is to reduce boilerplate in activity implementation and let developers define only what it matters in terms of business logic
Expand All @@ -54,16 +34,19 @@ export type SuccessOfActivityBody<B extends ActivityBody<unknown>> = B extends (
* @param OutputCodec an io-ts codec which maps the expected output structure
* @returns
*/
export const createActivity = <B extends ActivityBody<unknown>>(
export const createActivity = <
I extends unknown = unknown,
S extends ActivityResultSuccess = ActivityResultSuccess,
F extends ActivityResultFailure = ActivityResultFailure
>(
activityName: string,
InputCodec: t.Type<InputOfActivityBody<B>>,
OutputCodec: t.Type<SuccessOfActivityBody<B>>,
body: B
InputCodec: t.Type<I>,
OutputCodec: t.Type<S>,
body: ActivityBody<I, S, F>
) => async (
context: Context,
rawInput: unknown
): Promise<ActivityResultFailure | SuccessOfActivityBody<B>> => {
// TODO: define type variable TNext so that
): Promise<F | ActivityResultFailure | S | ActivityResultSuccess> => {
const logger = createLogger(context, activityName);

return fromEither(InputCodec.decode(rawInput))
Expand All @@ -74,7 +57,10 @@ export const createActivity = <B extends ActivityBody<unknown>>(
)
)
.chain(input => body({ context, logger, input }))
.map(OutputCodec.encode)
.fold(identity, identity)
.map(e => OutputCodec.encode(e))
.fold<F | ActivityResultFailure | S | ActivityResultSuccess>(
identity,
identity
)
.run();
};
20 changes: 9 additions & 11 deletions utils/durable/activities/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ export const createLogger = (
logPrefix: string = ""
): ActivityLogger =>
new Proxy(context.log, {
get: (t, key) => {
switch (key) {
case "info":
case "error":
case "warn":
case "verbose":
return (arg0: string) => t[key](`${logPrefix}|${arg0}`);
default:
return t[key];
}
}
get: (t, key) =>
// wrap logger functions
key === "info" || key === "error" || key === "info" || key === "verbose"
? (arg0: string) => t[key](`${logPrefix}|${arg0}`)
: // for other props, just return them
key in t
? t[key as keyof typeof t] // we need this cast in order to tell TS that key is actually part of Logger
: // else, the propo does not exists so it's just undefined
undefined
});
27 changes: 16 additions & 11 deletions utils/durable/orchestrators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {
ActivityBody,
ActivityResult,
ActivityResultFailure,
InputOfActivityBody,
SuccessOfActivityBody
ActivityResultSuccess
} from "../activities";
import { createLogger, IOrchestratorLogger } from "./log";
import {
Expand Down Expand Up @@ -77,6 +76,13 @@ export const createOrchestrator = <I, TNext = TNextDefault>(
}
};

export type CallableActivity<
I extends unknown = unknown,
S extends ActivityResultSuccess = ActivityResultSuccess,
// Failures aren't mapped as they are thrown
__ extends ActivityResultFailure = ActivityResultFailure
> = (context: IOrchestrationFunctionContext, input: I) => Generator<Task, S>;

/**
* Creates a callable for an activity to be used into an orchestrator function.
* Types are enforced from a ActivityBody definition so that they are bound to the actual activity implementation
Expand All @@ -85,15 +91,19 @@ export const createOrchestrator = <I, TNext = TNextDefault>(
* @param retryOptions if provided, the activity will be retried when failing
* @returns a generator function which takes an orchestrator context and an input for the activity
*/
export const callableActivity = <B extends ActivityBody<unknown> = undefined>(
export const callableActivity = <
I extends unknown = unknown,
S extends ActivityResultSuccess = ActivityResultSuccess,
__ extends ActivityResultFailure = ActivityResultFailure
>(
activityName: string,
OutputCodec: t.Type<SuccessOfActivityBody<B>>,
OutputCodec: t.Type<S>,
retryOptions?: RetryOptions
) =>
function*(
context: IOrchestrationFunctionContext,
input: InputOfActivityBody<B>
): Generator<Task, SuccessOfActivityBody<B>> {
input: I
): Generator<Task, S> {
const result = yield typeof retryOptions === "undefined"
? context.df.callActivity(activityName, input)
: context.df.callActivityWithRetry(activityName, retryOptions, input);
Expand Down Expand Up @@ -132,8 +142,3 @@ export const callableActivity = <B extends ActivityBody<unknown> = undefined>(
identity
);
};

export type CallableActivity<B extends ActivityBody<unknown> = undefined> = (
context: IOrchestrationFunctionContext,
input: InputOfActivityBody<B>
) => Generator<Task, SuccessOfActivityBody<B>>;

0 comments on commit 0d28679

Please sign in to comment.