
com.hpe.caf.services.job.queue.QueueServices Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2016-2024 Open Text.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hpe.caf.services.job.queue;
import static com.github.cafapi.correlation.constants.CorrelationIdConfigurationConstants.MDC_KEY;
import com.hpe.caf.api.Codec;
import com.hpe.caf.api.CodecException;
import com.hpe.caf.api.worker.TaskMessage;
import com.hpe.caf.api.worker.TaskStatus;
import com.hpe.caf.api.worker.TrackingInfo;
import com.hpe.caf.services.job.api.generated.model.WorkerAction;
import com.hpe.caf.services.configuration.AppConfig;
import com.hpe.caf.services.job.util.JobTaskId;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.MessageProperties;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import jakarta.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
/**
* This class is responsible sending task data to the target queue.
*/
public final class QueueServices implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(QueueServices.class);
private final Connection connection;
private final Channel publisherChannel;
private final String targetQueue;
private final Codec codec;
public QueueServices(Connection connection, Channel publisherChannel, String targetQueue, Codec codec) {
this.connection = connection;
this.publisherChannel = publisherChannel;
this.targetQueue = targetQueue;
this.codec = codec;
}
/**
* Send task data message to the target queue.
*/
public void sendMessage(
final String partitionId, String jobId, WorkerAction workerAction, AppConfig config, final boolean includeTrackingInfo
) throws IOException, InterruptedException, TimeoutException
{
// Generate a random task id.
String taskId = UUID.randomUUID().toString();
// Serialise the data payload. Encoding type is provided in the WorkerAction.
byte[] taskData = null;
//Check whether taskData is in the form of a string or object, and serialise/decode as appropriate.
final Object taskDataObj = workerAction.getTaskData();
if (taskDataObj instanceof String) {
final String taskDataStr = (String) taskDataObj;
final WorkerAction.TaskDataEncodingEnum encoding = workerAction.getTaskDataEncoding();
if (encoding == null || encoding == WorkerAction.TaskDataEncodingEnum.UTF8) {
taskData = taskDataStr.getBytes(StandardCharsets.UTF_8);
} else if (encoding == WorkerAction.TaskDataEncodingEnum.BASE64) {
taskData = Base64.decodeBase64(taskDataStr);
} else {
throw new RuntimeException("Unknown taskDataEncoding");
}
} else if (taskDataObj instanceof Map, ?>) {
try {
taskData = codec.serialise(taskDataObj);
} catch (CodecException e) {
throw new RuntimeException("Failed to serialise TaskData", e);
}
} else {
throw new RuntimeException("The taskData is an unexpected type");
}
//set up string for statusCheckUrl
String statusCheckUrl = UriBuilder.fromUri(config.getWebserviceUrl())
.path("partitions").path(partitionId)
.path("jobs").path(jobId)
.path("status").build().toString();
// Construct the task message.
final TrackingInfo trackingInfo = includeTrackingInfo ? new TrackingInfo(
new JobTaskId(partitionId, jobId).getMessageId(),
new Date(),
getStatusCheckIntervalMillis(config.getStatusCheckIntervalSeconds()),
statusCheckUrl, config.getTrackingPipe(), workerAction.getTargetPipe()) : null;
final TaskMessage taskMessage = new TaskMessage(
taskId,
workerAction.getTaskClassifier(),
workerAction.getTaskApiVersion(),
taskData,
TaskStatus.NEW_TASK,
Collections.emptyMap(),
targetQueue,
trackingInfo,
null,
MDC.get(MDC_KEY));
// Serialise the task message.
// Wrap any CodecException as a RuntimeException as it shouldn't happen
final byte[] taskMessageBytes;
try {
taskMessageBytes = codec.serialise(taskMessage);
} catch (CodecException e) {
throw new RuntimeException(e);
}
// Send the message.
try {
publishMessage(taskMessageBytes);
} catch (IOException | TimeoutException e) {
LOG.warn("Failed to publish message. Will retry", e);
publishMessage(taskMessageBytes);
}
}
public void publishMessage(final byte[] taskMessageBytes)
throws IOException, InterruptedException, TimeoutException
{
publisherChannel.basicPublish(
"", targetQueue, MessageProperties.PERSISTENT_TEXT_PLAIN, taskMessageBytes);
publisherChannel.waitForConfirmsOrDie(10000);
}
private static long getStatusCheckIntervalMillis(final String statusCheckIntervalSeconds){
try{
return Long.parseLong(statusCheckIntervalSeconds) * 1000;
} catch (NumberFormatException e) {
throw new RuntimeException("Please provide a valid integer for statusCheckIntervalSeconds. " + e);
}
}
/**
* Closes the queue connection.
*/
@Override
public void close() throws Exception {
try {
// Close channel.
if (publisherChannel != null) {
publisherChannel.close();
}
// Close connection.
if (connection != null) {
connection.close();
}
} catch (IOException | TimeoutException e) {
throw new Exception("Failed to close the queuing connection.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy