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

Support Proto 3 and 4 #2383

Merged
merged 9 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ or to *build.gradle*:

compile group: 'io.temporal', name: 'temporal-sdk', version: 'N.N.N'

## Protobuf 3.x vs 4.x

The Temporal Java SDK currently supports `protobuf-java` 3.x and 4.x. To support these, the Temporal Java SDK allows any protobuf library >= 3.25.
Temporal strongly recommends using the latest `protobuf-java` 4.x library unless you absolutely cannot.
If you cannot use protobuf-java 3.25 >=, you can try `temporal-shaded` which includes a shaded version of the `protobuf-java` library.

## Contributing

We'd love your help in improving the Temporal Java SDK. Please review our [contribution guidelines](CONTRIBUTING.md).
Expand Down
17 changes: 9 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
}

plugins {
id 'net.ltgt.errorprone' version '4.0.1' apply false
id 'net.ltgt.errorprone' version '4.1.0' apply false
id 'org.cadixdev.licenser' version '0.6.1'
id 'com.palantir.git-version' version "${palantirGitVersionVersion}" apply false
id 'io.github.gradle-nexus.publish-plugin' version '1.3.0'
Expand All @@ -29,7 +29,7 @@ allprojects {

ext {
// Platforms
grpcVersion = '1.54.1' // [1.38.0,) Needed for io.grpc.protobuf.services.HealthStatusManager
grpcVersion = '1.58.1' // [1.38.0,) Needed for io.grpc.protobuf.services.HealthStatusManager
jacksonVersion = '2.14.2' // [2.9.0,)
nexusVersion = '0.3.0-alpha'
// we don't upgrade to 1.10.x because it requires kotlin 1.6. Users may use 1.10.x in their environments though.
Expand All @@ -38,12 +38,13 @@ ext {
// stay on 1.x for a while to don't use any APIs from 2.x which may break our users which still stay on 1.x
// also slf4j 2.x is not compatible with spring boot 2.x
slf4jVersion = project.hasProperty("edgeDepsTest") ? '2.0.16' : '1.7.36' // [1.4.0,)
// [3.12.0,)
// 3.12 is brought by min gRPC 1.38.
// We can't move pass 3.22.0 because 3.22.2 deprecates some methods used by generated code produced by
// the old protoc we keep for compatibility of our generated code with old protobuf-java versions.
// Which leads to build failure because of -Werror.
protoVersion = '3.22.0'
// [3.25.5,)
// 3.25.5 is required because of our protoc compiler 25.x. The proto version must be the same or greater then the protoc version.
// We use this version of protoc because it will generate code that is compatible with protobuf-java 3.x and 4.x.
// We don't move past 3.25.x because the next version is a major version bump and we don't want to break our users.
//
// For more information see: https://github.com/grpc/grpc-java/issues/11015#issuecomment-2560196695
protoVersion = '3.25.5'
annotationApiVersion = '1.3.2'
guavaVersion = '32.0.1-jre' // [10.0,)
tallyVersion = '0.13.0' // [0.4.0,)
Expand Down
4 changes: 4 additions & 0 deletions temporal-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ dependencies {
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
testImplementation 'pl.pragmatists:JUnitParams:1.1.1'
testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: "${logbackVersion}"
if (project.hasProperty("edgeDepsTest")) {
testRuntimeOnly "com.google.protobuf:protobuf-java:4.29.3"
testRuntimeOnly "com.google.protobuf:protobuf-java-util:4.29.3"
}
}

// Temporal SDK supports Java 8 or later so to support virtual threads
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ public WorkflowStub newInstance(WorkflowOptions options) {
}

private void checkStarted() {
if (execution.get() == null || execution.get().getWorkflowId() == null) {
if (execution.get() == null) {
throw new IllegalStateException("Null workflowId. Was workflow started?");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,7 @@ public io.temporal.client.schedules.ScheduleSpec protoToScheduleSpec(
Objects.requireNonNull(scheduleSpec);
io.temporal.client.schedules.ScheduleSpec.Builder specBuilder =
io.temporal.client.schedules.ScheduleSpec.newBuilder()
.setTimeZoneName(
scheduleSpec.getTimezoneName() == null ? "" : scheduleSpec.getTimezoneName());
.setTimeZoneName(scheduleSpec.getTimezoneName());

if (scheduleSpec.hasJitter()) {
specBuilder.setJitter(ProtobufTimeUtils.toJavaDuration(scheduleSpec.getJitter()));
Expand Down Expand Up @@ -450,7 +449,7 @@ public io.temporal.client.schedules.ScheduleAction protoToAction(@Nonnull Schedu
wfOptionsBuilder.setWorkflowTaskTimeout(
ProtobufTimeUtils.toJavaDuration(startWfAction.getWorkflowTaskTimeout()));

if (startWfAction.getRetryPolicy() != null) {
if (startWfAction.hasRetryPolicy()) {
wfOptionsBuilder.setRetryOptions(
RetryOptionsUtils.toRetryOptions(startWfAction.getRetryPolicy()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public static WorkflowExecutionHistory fromJson(String serialized) {

private static void checkHistory(History history) {
List<HistoryEvent> events = history.getEventsList();
if (events == null || events.size() == 0) {
if (events.size() == 0) {
throw new IllegalArgumentException("Empty history");
}
HistoryEvent startedEvent = events.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,8 @@ public static String prettyPrintCommands(Iterable<Command> commands) {
}

/** Pretty prints a proto message. */
@SuppressWarnings("deprecation")
public static String prettyPrintObject(MessageOrBuilder object) {
return TextFormat.printToString(object);
return TextFormat.printer().printToString(object);
}

public static boolean containsEvent(List<HistoryEvent> history, EventType eventType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public void handleWorkflowExecutionUpdated(UpdateMessage updateMessage) {
Message protocolMessage = updateMessage.getMessage();
Request update = protocolMessage.getBody().unpack(Request.class);
Input input = update.getInput();
Optional<Payloads> args = Optional.ofNullable(input.getArgs());
Optional<Payloads> args = Optional.of(input.getArgs());
this.workflow.handleUpdate(
input.getName(),
update.getMeta().getUpdateId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ public WorkflowMetadata getWorkflowMetadata() {
WorkflowMetadata.Builder workflowMetadata = WorkflowMetadata.newBuilder();
WorkflowDefinition.Builder workflowDefinition = WorkflowDefinition.newBuilder();
// Set the workflow type
if (replayContext.getWorkflowType() != null
&& replayContext.getWorkflowType().getName() != null) {
if (replayContext.getWorkflowType() != null) {
workflowDefinition.setType(replayContext.getWorkflowType().getName());
}
// Set built in queries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,8 @@ private HistoryEvent newAttributes(EventType type, Object attributes) {
} else if (attributes instanceof Number) {
attributes = newAttributes(type, ((Number) attributes).intValue());
}
if (attributes instanceof com.google.protobuf.GeneratedMessageV3.Builder) {
attributes = ((com.google.protobuf.GeneratedMessageV3.Builder) attributes).build();
if (attributes instanceof com.google.protobuf.Message.Builder) {
attributes = ((com.google.protobuf.Message.Builder) attributes).build();
}
HistoryEvent.Builder result =
HistoryEvent.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ protected void update(UpdateMessage message, AsyncWorkflowBuilder<Void> builder)
(r) -> {
message.getCallbacks().complete(converter.toPayloads("update result"), null);
});
if (message.getMessage().getProtocolInstanceId() == "message_update") {
if (message.getMessage().getProtocolInstanceId().equals("message_update")) {
builder.add((r) -> stateMachines.completeWorkflow(Optional.empty()));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ public static class TestDynamicUpdateWorkflowImpl implements TestWorkflows.TestW
CompletablePromise<Void> promise = Workflow.newPromise();
List<String> updates = new ArrayList<>();

@Override
public String execute(String input) {
public TestDynamicUpdateWorkflowImpl() {
Workflow.registerListener(
new DynamicUpdateHandler() {
@Override
Expand All @@ -109,6 +108,10 @@ public Object handleExecute(String updateName, EncodedValues args) {
return "update:" + args.get(0, String.class);
}
});
}

@Override
public String execute(String input) {
promise.get();
return updates.stream().reduce("", (a, b) -> a + " " + b);
}
Expand Down
7 changes: 6 additions & 1 deletion temporal-serviceclient/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies {
api "io.grpc:grpc-stub" //Part of WorkflowServiceStubs API
api "io.grpc:grpc-netty-shaded" //Part of WorkflowServiceStubs API, specifically SslContext
api "io.grpc:grpc-services" //Standard gRPC HealthCheck Response class
api "io.grpc:grpc-inprocess" //For the in-process time skipping test server
api "com.google.protobuf:protobuf-java-util:$protoVersion" //proto request and response objects are a part of this module's API
if (JavaVersion.current().isJava9Compatible()) {
//needed for the generated grpc stubs and is not a part of JDK since java 9
Expand All @@ -28,6 +29,10 @@ dependencies {
testImplementation "junit:junit:${junitVersion}"
testImplementation "org.mockito:mockito-core:${mockitoVersion}"

if (project.hasProperty("edgeDepsTest")) {
testRuntimeOnly "com.google.protobuf:protobuf-java:4.29.3"
testRuntimeOnly "com.google.protobuf:protobuf-java-util:4.29.3"
}
testRuntimeOnly "ch.qos.logback:logback-classic:${logbackVersion}"
}

Expand Down Expand Up @@ -72,7 +77,7 @@ protobuf {
// protoc and protoc-gen-grpc-java versions are selected to be compatible
// with the oldest supported versions of protoc and grpc artifacts.
protoc {
artifact = 'com.google.protobuf:protoc:3.10.1' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
artifact = 'com.google.protobuf:protoc:3.25.5' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
}
plugins {
grpc {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ public class ProtoUtils {
* This method does exactly what {@link Any#pack(Message)} does. But it doesn't go into reflection
* to fetch the {@code descriptor}, which allows us to avoid a bunch of Graal reflection configs.
*/
public static <T extends GeneratedMessageV3> Any packAny(
T details, Descriptors.Descriptor descriptor) {
public static <T extends Message> Any packAny(T details, Descriptors.Descriptor descriptor) {
return Any.newBuilder()
.setTypeUrl("type.googleapis.com/" + descriptor.getFullName())
.setValue(details.toByteString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.Message;
import io.grpc.Status;
import io.temporal.internal.common.OptionsUtils;
import java.time.Duration;
Expand Down Expand Up @@ -57,7 +57,7 @@ public static RpcRetryOptions getDefaultInstance() {

public static class DoNotRetryItem {
private final Status.Code code;
private final Class<? extends GeneratedMessageV3> detailsClass;
private final Class<? extends Message> detailsClass;

/**
* @param code errors with this code will be considered non retryable. {@link
Expand All @@ -68,7 +68,7 @@ public static class DoNotRetryItem {
* retryable.
*/
public DoNotRetryItem(
@Nonnull Status.Code code, @Nullable Class<? extends GeneratedMessageV3> detailsClass) {
@Nonnull Status.Code code, @Nullable Class<? extends Message> detailsClass) {
this.code = Preconditions.checkNotNull(code, "code");
this.detailsClass = detailsClass;
}
Expand All @@ -77,7 +77,7 @@ public Status.Code getCode() {
return code;
}

public Class<? extends GeneratedMessageV3> getDetailsClass() {
public Class<? extends Message> getDetailsClass() {
return detailsClass;
}
}
Expand Down Expand Up @@ -252,7 +252,7 @@ public Builder setMaximumJitterCoefficient(double maximumJitterCoefficient) {
* with the {@code code} code are non retryable.
*/
public Builder addDoNotRetry(
Status.Code code, @Nullable Class<? extends GeneratedMessageV3> detailsClass) {
Status.Code code, @Nullable Class<? extends Message> detailsClass) {
doNotRetry.add(new DoNotRetryItem(code, detailsClass));
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class StatusUtils {
* @return true if the given failure is found, false otherwise
*/
public static boolean hasFailure(
StatusRuntimeException exception, Class<? extends GeneratedMessageV3> failureType) {
StatusRuntimeException exception, Class<? extends Message> failureType) {
Preconditions.checkNotNull(exception, "exception cannot be null");
com.google.rpc.Status status = StatusProto.fromThrowable(exception);
if (status.getDetailsCount() == 0) {
Expand All @@ -52,7 +52,7 @@ public static boolean hasFailure(
/**
* @return a failure of a given type from the StatusRuntimeException object
*/
public static <T extends GeneratedMessageV3> T getFailure(
public static <T extends Message> T getFailure(
StatusRuntimeException exception, Class<T> failureType) {
Preconditions.checkNotNull(exception, "exception cannot be null");
com.google.rpc.Status status = StatusProto.fromThrowable(exception);
Expand All @@ -72,7 +72,7 @@ public static <T extends GeneratedMessageV3> T getFailure(
}

/** Create StatusRuntimeException with given details. */
public static <T extends GeneratedMessageV3> StatusRuntimeException newException(
public static <T extends Message> StatusRuntimeException newException(
io.grpc.Status status, T details, Descriptors.Descriptor detailsDescriptor) {
Preconditions.checkNotNull(status, "status cannot be null");
Status protoStatus =
Expand Down
2 changes: 1 addition & 1 deletion temporal-test-server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ protobuf {
// protoc and protoc-gen-grpc-java versions are selected to be compatible
// with the oldest supported versions of protoc and grpc artifacts.
protoc {
artifact = 'com.google.protobuf:protoc:3.10.1' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
artifact = 'com.google.protobuf:protoc:3.25.5' + (System.getProperty("os.arch") == 'aarch64' && System.getProperty("os.name") == 'Mac OS X' ? ':osx-x86_64' : '')
}
plugins {
grpc {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ BackoffInterval getBackoffIntervalInSeconds(
RetryPolicy retryPolicy = getRetryPolicy();
// check if error is non-retryable
List<String> nonRetryableErrorTypes = retryPolicy.getNonRetryableErrorTypesList();
if (nonRetryableErrorTypes != null && errorType.isPresent()) {
if (errorType.isPresent()) {
String type = errorType.get();
for (String err : nonRetryableErrorTypes) {
if (type.equals(err)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3396,7 +3396,6 @@ private void addExecutionSignaledEvent(
RequestContext ctx, SignalWorkflowExecutionRequest signalRequest) {
WorkflowExecutionSignaledEventAttributes.Builder a =
WorkflowExecutionSignaledEventAttributes.newBuilder()
.setInput(startRequest.getInput())
.setIdentity(signalRequest.getIdentity())
.setInput(signalRequest.getInput())
.setSignalName(signalRequest.getSignalName());
Expand All @@ -3412,7 +3411,6 @@ private void addExecutionSignaledByExternalEvent(
RequestContext ctx, SignalExternalWorkflowExecutionCommandAttributes d) {
WorkflowExecutionSignaledEventAttributes.Builder a =
WorkflowExecutionSignaledEventAttributes.newBuilder()
.setInput(startRequest.getInput())
.setInput(d.getInput())
.setSignalName(d.getSignalName());
HistoryEvent executionSignaled =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1348,8 +1348,7 @@ public void signalWithStartWorkflowExecution(
.setWorkflowIdReusePolicy(r.getWorkflowIdReusePolicy())
.setIdentity(r.getIdentity())
.setWorkflowType(r.getWorkflowType())
.setCronSchedule(r.getCronSchedule())
.setRequestId(r.getRequestId());
.setCronSchedule(r.getCronSchedule());
if (r.hasRetryPolicy()) {
startRequest.setRetryPolicy(r.getRetryPolicy());
}
Expand Down
Loading
Loading