Skip to content

Commit

Permalink
feat(designer): adding maxWaitingRuns to Concurrency Settings (#4988)
Browse files Browse the repository at this point in the history
add max wait runs
  • Loading branch information
Eric-B-Wu committed Jun 18, 2024
1 parent d6b0e30 commit 691fdbb
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 34 deletions.
6 changes: 6 additions & 0 deletions Localize/lang/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@
"EptZhD": "Enter a valid table.",
"EqX3Mi": "Set up these connections to use them in your flow.",
"EurkzL": "Please select yes or no",
"Eyxa6q": "The number of workflow instances that can wait to run when your current workflow instance is already running the maximum concurrent instances.",
"F3IDl8": "Required. The number of a specified time unit to add.",
"F6+icQ": "Retry Policy Maximum Interval is invalid, must match ISO 8601 duration format",
"F9dR1Q": "Add",
Expand Down Expand Up @@ -590,6 +591,7 @@
"MmldTM": "No action to paste",
"MnThTq": "Insert function",
"MsCHhQ": "Timed Out",
"MtWzvX": "Enter a positive integer between {min} and {max}",
"N0pS6Y": "Target schema",
"N2CF0J": "Required. The key name of the form data values to return.",
"N4dEVo": "Headers",
Expand Down Expand Up @@ -1345,6 +1347,7 @@
"_EptZhD.comment": "Error validation message for JSONs",
"_EqX3Mi.comment": "Chatbot connections set up description text",
"_EurkzL.comment": "Placeholder description for a newly inserted Boolean parameter",
"_Eyxa6q.comment": "tooltip of maximum waiting runs setting",
"_F3IDl8.comment": "Required integer parameter to add to time",
"_F6+icQ.comment": "error message for maximum invalid retry interval",
"_F9dR1Q.comment": "Add",
Expand Down Expand Up @@ -1521,6 +1524,7 @@
"_MmldTM.comment": "Text for tooltip when there is no action to paste",
"_MnThTq.comment": "Message to insert function",
"_MsCHhQ.comment": "The status message to show in monitoring view.",
"_MtWzvX.comment": "descriptio of maximum waiting runs setting",
"_N0pS6Y.comment": "Target schema",
"_N2CF0J.comment": "Required string parameter to be used as key for triggerFormDataMultiValues function",
"_N4dEVo.comment": "Display name for headers in outputs",
Expand Down Expand Up @@ -1967,6 +1971,7 @@
"_eT+b9W.comment": "Required number parameter to be divided by in div function",
"_egLI8P.comment": "Required start index parameter required to obtain substring",
"_ehIBkh.comment": "Placeholder for integer text field",
"_ei1KmG.comment": "Label for maximum waiting runs",
"_elD6+N.comment": "Command for italic text for Mac users",
"_en/5A3.comment": "Button text to reassign actions",
"_eo1YKX.comment": "description of the split on setting",
Expand Down Expand Up @@ -2623,6 +2628,7 @@
"eT+b9W": "Required. The number to divide the Dividend by.",
"egLI8P": "Required. The index of where the substring begins in parameter 1.",
"ehIBkh": "Enter an integer",
"ei1KmG": "Maximum Waiting Runs",
"elD6+N": "Italic (⌘I)",
"en/5A3": "Reassign",
"eo1YKX": "Enable split-on to start an instance of the workflow per item in the selected array. Each instance can also have a distinct tracking id",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ import {
getReactQueryClient,
serializeBJSWorkflow,
store as DesignerStore,
Constants,
getSKUDefaultHostOptions,
} from '@microsoft/logic-apps-designer';
import axios from 'axios';
import isEqual from 'lodash.isequal';
Expand Down Expand Up @@ -311,7 +313,7 @@ const DesignerEditor = () => {
suppressDefaultNodeSelectFunctionality: suppressDefaultNodeSelect,
hostOptions: {
...hostOptions,
recurrenceInterval: { interval: 1, frequency: 'Minute' },
...getSKUDefaultHostOptions(Constants.SKU.STANDARD),
},
showConnectionsPanel,
showPerformanceDebug,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
getReactQueryClient,
serializeBJSWorkflow,
store as DesignerStore,
getSKUDefaultHostOptions,
Constants,
} from '@microsoft/logic-apps-designer';
import * as React from 'react';
Expand Down Expand Up @@ -223,7 +224,7 @@ const DesignerEditorConsumption = () => {
suppressDefaultNodeSelectFunctionality: suppressDefaultNodeSelect,
hostOptions: {
...hostOptions,
recurrenceInterval: Constants.RECURRENCE_OPTIONS.CONSUMPTION,
...getSKUDefaultHostOptions(Constants.SKU.CONSUMPTION),
},
showPerformanceDebug,
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Input, Label } from '@fluentui/react-components';
import type { InputOnChangeData } from '@fluentui/react-components';
import type { SettingProps } from './';
import { TextField } from '@fluentui/react';
import type React from 'react';
import { useState } from 'react';
import type { FormEvent } from 'react';
Expand All @@ -8,12 +9,15 @@ export type TextInputChangeHandler = (event: FormEvent<HTMLInputElement | HTMLTe

export interface SettingTextFieldProps extends SettingProps {
id?: string;
value: string;
value: string | number;
defaultValue?: string;
placeholder?: string;
label?: string;
readOnly?: boolean;
required?: boolean;
max?: number;
min?: number;
type?: 'text' | 'number';
onValueChange?: TextInputChangeHandler;
}

Expand All @@ -28,25 +32,30 @@ export const SettingTextField: React.FC<SettingTextFieldProps> = ({
onValueChange,
defaultValue,
ariaLabel,
max,
min,
type,
}): JSX.Element | null => {
const [textValue, setTextValue] = useState(value ?? '');
const handleTextInputChange = (_: FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string | undefined): void => {
setTextValue(newValue ?? '');
onValueChange?.(_, newValue);
const handleTextInputChange = (_e: React.ChangeEvent<HTMLInputElement>, data: InputOnChangeData): void => {
setTextValue(data.value);
onValueChange?.(_e, data.value);
};

return (
<>
{customLabel ? customLabel : null}
<TextField
{customLabel ? customLabel : <Label> {label} </Label>}
<Input
type={type}
className="msla-setting-section-textField"
id={id}
label={customLabel ? '' : label}
ariaLabel={ariaLabel}
value={textValue}
aria-label={ariaLabel}
value={textValue.toString()}
defaultValue={defaultValue}
placeholder={placeholder}
readOnly={readOnly}
max={max}
min={min}
required={required}
onChange={handleTextInputChange}
/>
Expand Down
9 changes: 9 additions & 0 deletions libs/designer/src/lib/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export default {
PREMIUM: 'PREMIUM',
STANDARD: 'STANDARD',
},
SKU: {
STANDARD: 'standard',
CONSUMPTION: 'consumption',
},
ACTION_PALETTE_KEY: 'actionpalettekey',
ARM_RESOURCE: {
FUNCTION: {
Expand Down Expand Up @@ -840,6 +844,7 @@ export default {
CONCURRENCY: 'concurrency',
REPETITIONS: 'repetitions',
RUNS: 'runs',
MAXIMUM_WAITING_RUNS: 'maximumWaitingRuns',
STATIC_RESULT: 'staticResult',
SECURE_DATA: 'secureData',
UPLOAD_CHUNK_SIZE: 'uploadChunkSizeInMB',
Expand All @@ -853,6 +858,10 @@ export default {
AUTOLOAD: '@autoload()',
},
},
MAXIMUM_WAITING_RUNS: {
CONSUMPTION: { min: 10, max: 200 },
DEFAULT: { min: 10, max: 100 },
},
SWAGGER,
SYSTEM_ASSIGNED_MANAGED_IDENTITY: 'SystemAssigned_Managed_Identity',
TIP_LOGGING_KEYS: {
Expand Down
15 changes: 15 additions & 0 deletions libs/designer/src/lib/common/utilities/Utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import toTitleCase from 'to-title-case';
import constants from '../constants';

export const titleCase = (s: string) => toTitleCase(s);

export const isOpenApiSchemaVersion = (definition: any) => definition?.$schema?.includes('2023-01-31-preview');

export const getSKUDefaultHostOptions = (sku: string) => {
switch (sku) {
case constants.SKU.CONSUMPTION:
return {
recurrenceInterval: constants.RECURRENCE_OPTIONS.CONSUMPTION,
maximumWaitingRuns: constants.MAXIMUM_WAITING_RUNS.CONSUMPTION,
};
case constants.SKU.STANDARD:
return { recurrenceInterval: constants.RECURRENCE_OPTIONS.STANDARD, maximumWaitingRuns: constants.MAXIMUM_WAITING_RUNS.DEFAULT };
default:
return {};
}
};
8 changes: 6 additions & 2 deletions libs/designer/src/lib/core/actions/bjsworkflow/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -919,25 +919,29 @@ const getSerializedRuntimeConfiguration = (

if (!isTrigger) {
if (!settings.sequential) {
const repetitions = settings.concurrency?.value?.enabled ? settings.concurrency.value.value : undefined;
const repetitions = settings.concurrency?.value?.enabled ? settings.concurrency.value.runs : undefined;
const maximumWaitingRuns = settings.concurrency?.value?.enabled ? settings.concurrency.value.maximumWaitingRuns : undefined;

if (repetitions !== undefined) {
safeSetObjectPropertyValue(
runtimeConfiguration,
[Constants.SETTINGS.PROPERTY_NAMES.CONCURRENCY, Constants.SETTINGS.PROPERTY_NAMES.REPETITIONS],
repetitions
);
safeSetObjectPropertyValue(runtimeConfiguration, [Constants.SETTINGS.PROPERTY_NAMES.MAXIMUM_WAITING_RUNS], maximumWaitingRuns);
}
}
} else if (!settings.singleInstance) {
const runs = settings.concurrency?.value?.enabled ? settings.concurrency.value.value : undefined;
const runs = settings.concurrency?.value?.enabled ? settings.concurrency.value.runs : undefined;
const maximumWaitingRuns = settings.concurrency?.value?.enabled ? settings.concurrency.value.maximumWaitingRuns : undefined;

if (runs !== undefined) {
safeSetObjectPropertyValue(
runtimeConfiguration,
[Constants.SETTINGS.PROPERTY_NAMES.CONCURRENCY, Constants.SETTINGS.PROPERTY_NAMES.RUNS],
runs
);
safeSetObjectPropertyValue(runtimeConfiguration, [Constants.SETTINGS.PROPERTY_NAMES.MAXIMUM_WAITING_RUNS], maximumWaitingRuns);
}
}

Expand Down
30 changes: 24 additions & 6 deletions libs/designer/src/lib/core/actions/bjsworkflow/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export interface SimpleSetting<T> {
value?: T;
}

interface ConcurrencySettings {
enabled: boolean;
runs?: number;
maximumWaitingRuns?: number;
}

interface CorrelationSettings {
clientTrackingId?: string;
}
Expand Down Expand Up @@ -86,7 +92,7 @@ export interface Settings {
disableAutomaticDecompression?: SettingData<boolean>;
splitOn?: SettingData<SimpleSetting<string>>;
retryPolicy?: SettingData<RetryPolicy>;
concurrency?: SettingData<SimpleSetting<number>>;
concurrency?: SettingData<ConcurrencySettings>;
requestOptions?: SettingData<RequestOptions>;
sequential?: boolean; // NOTE: This should be removed when logs indicate that none has the definition in the old format.
singleInstance?: boolean; // NOTE: This should be removed when logs indicate that none has the definition in the old format.
Expand Down Expand Up @@ -384,7 +390,7 @@ const getConcurrency = (
nodeType: string,
manifest?: OperationManifest,
definition?: LogicAppsV2.OperationDefinition
): SimpleSetting<number> | undefined => {
): ConcurrencySettings | undefined => {
if (!isConcurrencySupported(isTrigger, nodeType, manifest)) {
return undefined;
}
Expand All @@ -395,37 +401,49 @@ const getConcurrency = (
if (isOperationOptionSet(Constants.SETTINGS.OPERATION_OPTIONS.SEQUENTIAL, operationOptions)) {
return {
enabled: true,
value: 1,
runs: 1,
};
}

let concurrencyRepetitions: number | undefined;
let maximumWaitingRuns: number | undefined;
if (definition) {
const runtimeConfiguration = getObjectPropertyValue(definition as any, [Constants.SETTINGS.PROPERTY_NAMES.RUNTIME_CONFIGURATION]);
concurrencyRepetitions = getObjectPropertyValue(runtimeConfiguration, [
Constants.SETTINGS.PROPERTY_NAMES.CONCURRENCY,
Constants.SETTINGS.PROPERTY_NAMES.REPETITIONS,
]);
concurrencyRepetitions = getObjectPropertyValue(runtimeConfiguration, [
Constants.SETTINGS.PROPERTY_NAMES.CONCURRENCY,
Constants.SETTINGS.PROPERTY_NAMES.MAXIMUM_WAITING_RUNS,
]);
}

return typeof concurrencyRepetitions === 'number' ? { enabled: true, value: concurrencyRepetitions } : { enabled: false };
return typeof concurrencyRepetitions === 'number'
? { enabled: true, runs: concurrencyRepetitions, maximumWaitingRuns }
: { enabled: false };
}
if (isOperationOptionSet(Constants.SETTINGS.OPERATION_OPTIONS.SINGLE_INSTANCE, operationOptions)) {
return {
enabled: true,
value: 1,
runs: 1,
};
}

let concurrencyRuns: number | undefined;
let maximumWaitingRuns: number | undefined;
if (definition) {
concurrencyRuns = getObjectPropertyValue(getRuntimeConfiguration(definition), [
Constants.SETTINGS.PROPERTY_NAMES.CONCURRENCY,
Constants.SETTINGS.PROPERTY_NAMES.RUNS,
]);
maximumWaitingRuns = getObjectPropertyValue(getRuntimeConfiguration(definition), [
Constants.SETTINGS.PROPERTY_NAMES.CONCURRENCY,
Constants.SETTINGS.PROPERTY_NAMES.MAXIMUM_WAITING_RUNS,
]);
}

return typeof concurrencyRuns === 'number' ? { enabled: true, value: concurrencyRuns } : { enabled: false };
return typeof concurrencyRuns === 'number' ? { enabled: true, runs: concurrencyRuns, maximumWaitingRuns } : { enabled: false };
};

const isConcurrencySupported = (isTrigger: boolean, nodeType: string, manifest?: OperationManifest): boolean => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
ICustomCodeService,
LogicApps,
} from '@microsoft/logic-apps-shared';
import type { MaximumWaitingRunsMetadata } from '../../../ui/settings';

type PANEL_TAB_NAMES = keyof typeof CONSTANTS.PANEL_TAB_NAMES;

Expand All @@ -35,6 +36,7 @@ export interface DesignerOptionsState {
displayRuntimeInfo: boolean; // show info about where the action is run(i.e. InApp/Shared/Custom)
suppressCastingForSerialize?: boolean; // suppress casting for serialize
recurrenceInterval?: LogicApps.Recurrence;
maxWaitingRuns?: MaximumWaitingRunsMetadata; // min and max of Maximum Waiting Runs Concurrency Setting
forceEnableSplitOn?: boolean; // force enable split on (by default it is disabled on stateless workflows)
hideUTFExpressions?: boolean; // hide UTF expressions in template functions
stringOverrides?: Record<string, string>; // string overrides for localization
Expand Down
2 changes: 1 addition & 1 deletion libs/designer/src/lib/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ export { default as Constants } from './common/constants';
export { serializeWorkflow as serializeBJSWorkflow } from './core/actions/bjsworkflow/serializer';
export { updateCallbackUrl } from './core/actions/bjsworkflow/initialize';
export { ReactQueryProvider } from './core/ReactQueryProvider';
export { isOpenApiSchemaVersion } from './common/utilities/Utils';
export { isOpenApiSchemaVersion, getSKUDefaultHostOptions } from './common/utilities/Utils';
Loading

0 comments on commit 691fdbb

Please sign in to comment.