Add temporal integration#9
Conversation
…n features - Add WorkflowCodeAnalyzer for validating @process and @activity function signatures. - Introduce WorkflowCodeModifier to transform workflow process functions and register them. - Create WorkflowCompilerPlugin to integrate the analyzer and modifier into the compilation process. - Define WorkflowConstants for shared constants used across the plugin. - Implement WorkflowModifierContext to hold information about process modifications. - Develop WorkflowSourceModifier to handle AST transformations for process functions. - Add WorkflowValidatorTask for validating function signatures based on workflow semantics. - Create ModuleUtils for managing workflow module information. - Enhance ProcessRegistry to track activities associated with processes. - Implement native functions in WorkflowNative for registering processes and retrieving registered workflows. - Add functionality to clear the registry for testing purposes.
…rgument transformation in workflow source modifier
…rgument transformation in workflow source modifier
- Introduced tests for invalid workflow process scenarios: - `invalid_call_activity_no_annotation`: Ensures that calling a non-activity function results in WORKFLOW_107 error. - `invalid_direct_activity_call`: Validates that direct calls to activity functions raise WORKFLOW_108 error. - Updated valid process examples to use ctx->callActivity() pattern for invoking activity functions. - Enhanced the ProcessFunctionAnalysisTask to support validation of ctx->callActivity() calls, ensuring the first argument is an activity function. - Implemented WorkflowValidatorTask to check for direct calls to activity functions and validate callActivity usage. - Modified WorkflowSourceModifier to remove direct activity call transformations, enforcing ctx->callActivity() usage. - Added native implementation for executing activity functions within the workflow context, ensuring proper error handling. - Updated utility classes to check for Context parameters in process functions and convert types appropriately.
- Implemented various workflows including error handling, multi-activity, order processing, and simple workflows. - Created corresponding test cases to validate the functionality of each workflow. - Introduced a configuration file for Temporal server settings. - Added utility functions for generating unique workflow IDs. - Updated the test server to use a different default port for better compatibility. - Enhanced the workflow runtime to automatically start the singleton worker if not already running.
- Added SignalFutureNative class to handle signal awaiting using Temporal's CompletablePromise. - Introduced TemporalFutureValue class to bridge Temporal's CompletablePromise with Ballerina's wait mechanism. - Enhanced WorkflowRuntime to support sending events with optional signal names. - Updated WorkflowNative to allow sending events with inferred signal names from event data structure. - Created EventExtractor utility methods to infer signal names and get events record type from process functions. - Added EventFutureCreator to create TemporalFutureValue instances for workflow events. - Modified WorkflowWorkerNative to inject events record into workflow function calls.
There was a problem hiding this comment.
Pull request overview
This PR adds Temporal workflow orchestration capabilities to the Ballerina workflow module, introducing durable workflow execution with signal handling, activity management, and integration testing infrastructure.
Changes:
- Added Temporal SDK integration with native Java implementations for workflow runtime, activities, and signal handling
- Implemented compiler plugin for validating and transforming
@Processand@Activityannotated functions - Created comprehensive integration test infrastructure with embedded Temporal test server
- Enhanced workflow context with future-based signal handling using Temporal's CompletablePromise
- Added type conversion utilities and error serialization for crossing Ballerina-Java-Temporal boundaries
Reviewed changes
Copilot reviewed 105 out of 107 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| spotbugs-exclude.xml | Added exclusions for singleton patterns, lazy initialization, and intentional design patterns |
| settings.gradle | Added workflow-native-test and workflow-integration-tests modules |
| native/build.gradle | Added Temporal SDK, gRPC, Jackson, and supporting dependencies |
| native/src/main/java/**/*.java | Core native implementations for Temporal integration (runtime, context, signals, futures) |
| native-test/**/*.java | Embedded Temporal test server for integration testing |
| compiler-plugin/**/*.java | Compiler plugin for validating workflow annotations and transforming code |
| compiler-plugin-tests/** | Test cases for compiler plugin validation |
| integration-tests/** | Comprehensive workflow integration tests with signal handling |
| ballerina/** | Ballerina module API, types, context client, and configuration |
| build.gradle | Shared test server infrastructure with automatic lifecycle management |
| .github/** | Documentation and code ownership updates |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…lowPluginUtils for subtype checking
…ve image properties
…rkflows - Added `CorrelationExtractor` utility class to extract correlation keys from workflow input and signal data. - Introduced `SearchAttributeRegistry` to manage registration of Temporal Search Attributes for correlation keys. - Enhanced `EventExtractor` to retrieve input and signal record types for correlation key extraction. - Updated `WorkflowWorkerNative` to initialize `SearchAttributeRegistry` and register correlation keys during process registration. - Implemented upsert functionality for correlation keys as Temporal Search Attributes in `WorkflowWorkerNative`. - Added support for UUID v7 generation in `CorrelationExtractor` for unique workflow IDs. - Updated SpotBugs exclusions to account for uncalled private methods related to correlation support.
… logging to debug level
- Implement CRM Sync workflow with activities for validating, finding, creating, and updating contacts. - Create HTTP service for triggering CRM sync workflows and retrieving results. - Add mock CRM backend for simulating contact operations. - Introduce order processing workflow with activities for checking inventory and reserving stock. - Develop HTTP service for order processing with endpoints for placing orders and checking status. - Implement signal-based payment confirmation workflow with future-based handling. - Add comprehensive README documentation for both CRM Sync and Order Processing samples.
| TypeSymbol eventsType = null; | ||
|
|
||
| // Check first parameter - could be Context, input, or events | ||
| if (paramIndex < params.size()) { |
|
|
||
| // Check remaining parameters - they can be input and/or events | ||
| // The order should be: [Context], [input], [events] | ||
| while (paramIndex < params.size()) { |
There was a problem hiding this comment.
Shall we try to remove the while loop here? IMO while loop is an overkill here
| if (returnTypeOpt.isPresent()) { | ||
| TypeSymbol returnType = returnTypeOpt.get(); | ||
| if (!WorkflowPluginUtils.isSubtypeOfAnydataOrError(returnType, context.semanticModel())) { | ||
| reportDiagnostic(context, functionNode, WorkflowConstants.WORKFLOW_105, |
There was a problem hiding this comment.
Should use the return type desc location as the diagnostic location
| paramIndex++; | ||
| } else if (looksLikeContextType(firstParamType)) { | ||
| // First param looks like it should be Context but isn't the right type | ||
| reportDiagnostic(context, functionNode, WorkflowConstants.WORKFLOW_100, |
There was a problem hiding this comment.
We need to use relevent param location for diagnostic. let's update the other places as well
There was a problem hiding this comment.
Let's create a seperate issue to track this requirment.
…e related documentation and tests
…pdate related tests and documentation
- Updated SignalAwaitWrapper to use Java records for SignalData and ContextInfo, improving code clarity and reducing boilerplate. - Removed the SignalFutureNative class as it was redundant with the new signal handling approach. - Enhanced TemporalFutureValue and WorkflowContextNative to utilize new record structures. - Simplified event handling in EventInfo and WorkflowWorkerNative by leveraging record features. - Improved type handling in SearchAttributeRegistry and TypesUtil, adopting modern Java features for better readability. - Cleaned up unused methods and comments across various classes to streamline the codebase.
| if (!arguments.isEmpty()) { | ||
| FunctionArgumentNode firstArg = arguments.get(0); | ||
| if (firstArg instanceof PositionalArgumentNode) { | ||
| PositionalArgumentNode posArg = (PositionalArgumentNode) firstArg; |
There was a problem hiding this comment.
Variable 'posArg' can be replaced with pattern variable
| String methodName = remoteCallNode.methodName().name().text(); | ||
|
|
||
| // Check if this is a callActivity call | ||
| if (WorkflowConstants.CALL_ACTIVITY_FUNCTION.equals(methodName)) { |
There was a problem hiding this comment.
This does not check for the expression type being workoflow:Context. Samples like below get the unwanted errors
A a = new;
_ = a->callActivity(4);There was a problem hiding this comment.
Why we need to do that, that is handled by the type checker. isn't it ?
There was a problem hiding this comment.
No its a valid ballerina code
client class A {
remote function callActivity(int activityFunction) {
}
}| FunctionArgumentNode firstArg = arguments.get(0); | ||
| if (firstArg instanceof PositionalArgumentNode) { | ||
| PositionalArgumentNode posArg = (PositionalArgumentNode) firstArg; | ||
| ExpressionNode expression = posArg.expression(); |
There was a problem hiding this comment.
| ExpressionNode expression = posArg.expression(); | |
| ExpressionNode activityFuncExpr = posArg.expression(); |
| return paramNames; | ||
| } | ||
|
|
||
| PositionalArgumentNode posArg = (PositionalArgumentNode) paramsArg; |
There was a problem hiding this comment.
Variable 'posArg' can be replaced with pattern variable
…and multiple no-arg activities. Refactor diagnostic codes to use WorkflowDiagnostic enum and update related validation logic. Introduce new test cases for invalid no-arg activity scenarios.
| * Validates @Process function signature according to Agent.md semantics. | ||
| * <ul> | ||
| * <li>Optional first parameter: workflow:Context</li> | ||
| * <li>Optional input parameter: subtype of anydata</li> |
There was a problem hiding this comment.
We discussed not to disallow the no corelation for now right?. Because of that input should be required not optional
Fixes ballerina-platform/ballerina-library#8424