Search in sources :

Example 1 with Function

use of org.apache.pulsar.functions.proto.Function in project incubator-pulsar by apache.

the class MembershipManager method checkFailures.

public void checkFailures(FunctionMetaDataManager functionMetaDataManager, FunctionRuntimeManager functionRuntimeManager, SchedulerManager schedulerManager) {
    Set<String> currentMembership = this.getCurrentMembership().stream().map(entry -> entry.getWorkerId()).collect(Collectors.toSet());
    List<Function.FunctionMetaData> functionMetaDataList = functionMetaDataManager.getAllFunctionMetaData();
    Map<String, Function.FunctionMetaData> functionMetaDataMap = new HashMap<>();
    for (Function.FunctionMetaData entry : functionMetaDataList) {
        functionMetaDataMap.put(FunctionConfigUtils.getFullyQualifiedName(entry.getFunctionConfig()), entry);
    }
    Map<String, Map<String, Function.Assignment>> currentAssignments = functionRuntimeManager.getCurrentAssignments();
    Map<String, Function.Assignment> assignmentMap = new HashMap<>();
    for (Map<String, Function.Assignment> entry : currentAssignments.values()) {
        assignmentMap.putAll(entry);
    }
    long currentTimeMs = System.currentTimeMillis();
    // remove functions
    Iterator<Map.Entry<Function.Instance, Long>> it = unsignedFunctionDurations.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Function.Instance, Long> entry = it.next();
        String fullyQualifiedFunctionName = FunctionConfigUtils.getFullyQualifiedName(entry.getKey().getFunctionMetaData().getFunctionConfig());
        String fullyQualifiedInstanceId = Utils.getFullyQualifiedInstanceId(entry.getKey());
        // remove functions that don't exist anymore
        if (!functionMetaDataMap.containsKey(fullyQualifiedFunctionName)) {
            it.remove();
        } else {
            // remove functions that have been scheduled
            Function.Assignment assignment = assignmentMap.get(fullyQualifiedInstanceId);
            if (assignment != null) {
                String assignedWorkerId = assignment.getWorkerId();
                // check if assigned to worker that has failed
                if (currentMembership.contains(assignedWorkerId)) {
                    it.remove();
                }
            }
        }
    }
    // check for function instances that haven't been assigned
    for (Function.FunctionMetaData functionMetaData : functionMetaDataList) {
        Collection<Function.Assignment> assignments = FunctionRuntimeManager.findFunctionAssignments(functionMetaData.getFunctionConfig().getTenant(), functionMetaData.getFunctionConfig().getNamespace(), functionMetaData.getFunctionConfig().getName(), currentAssignments);
        Set<Function.Instance> assignedInstances = assignments.stream().map(assignment -> assignment.getInstance()).collect(Collectors.toSet());
        Set<Function.Instance> instances = new HashSet<>(SchedulerManager.computeInstances(functionMetaData));
        for (Function.Instance instance : instances) {
            if (!assignedInstances.contains(instance)) {
                if (!this.unsignedFunctionDurations.containsKey(instance)) {
                    this.unsignedFunctionDurations.put(instance, currentTimeMs);
                }
            }
        }
    }
    // check failed nodes
    for (Map.Entry<String, Map<String, Function.Assignment>> entry : currentAssignments.entrySet()) {
        String workerId = entry.getKey();
        Map<String, Function.Assignment> assignmentEntries = entry.getValue();
        if (!currentMembership.contains(workerId)) {
            for (Function.Assignment assignmentEntry : assignmentEntries.values()) {
                Function.Instance instance = assignmentEntry.getInstance();
                if (!this.unsignedFunctionDurations.containsKey(instance)) {
                    this.unsignedFunctionDurations.put(instance, currentTimeMs);
                }
            }
        }
    }
    boolean triggerScheduler = false;
    // check unassigned
    Collection<Function.Instance> needSchedule = new LinkedList<>();
    Collection<Function.Assignment> needRemove = new LinkedList<>();
    for (Map.Entry<Function.Instance, Long> entry : this.unsignedFunctionDurations.entrySet()) {
        Function.Instance instance = entry.getKey();
        long unassignedDurationMs = entry.getValue();
        if (currentTimeMs - unassignedDurationMs > this.workerConfig.getRescheduleTimeoutMs()) {
            needSchedule.add(instance);
            // remove assignment from failed node
            Function.Assignment assignment = assignmentMap.get(Utils.getFullyQualifiedInstanceId(instance));
            if (assignment != null) {
                needRemove.add(assignment);
            }
            triggerScheduler = true;
        }
    }
    if (!needRemove.isEmpty()) {
        functionRuntimeManager.removeAssignments(needRemove);
    }
    if (triggerScheduler) {
        log.info("Functions that need scheduling/rescheduling: {}", needSchedule);
        schedulerManager.schedule();
    }
}
Also used : Getter(lombok.Getter) PersistentTopicStats(org.apache.pulsar.common.policies.data.PersistentTopicStats) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) PulsarAdmin(org.apache.pulsar.client.admin.PulsarAdmin) ConsumerEventListener(org.apache.pulsar.client.api.ConsumerEventListener) HashSet(java.util.HashSet) AccessLevel(lombok.AccessLevel) FunctionConfigUtils(org.apache.pulsar.functions.utils.FunctionConfigUtils) Map(java.util.Map) ToString(lombok.ToString) LinkedList(java.util.LinkedList) PulsarClient(org.apache.pulsar.client.api.PulsarClient) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) Function(org.apache.pulsar.functions.proto.Function) Iterator(java.util.Iterator) PulsarAdminException(org.apache.pulsar.client.admin.PulsarAdminException) Collection(java.util.Collection) Set(java.util.Set) ConsumerConfiguration(org.apache.pulsar.client.api.ConsumerConfiguration) SubscriptionType(org.apache.pulsar.client.api.SubscriptionType) Collectors(java.util.stream.Collectors) Consumer(org.apache.pulsar.client.api.Consumer) List(java.util.List) Slf4j(lombok.extern.slf4j.Slf4j) ConsumerStats(org.apache.pulsar.common.policies.data.ConsumerStats) VisibleForTesting(com.google.common.annotations.VisibleForTesting) AllArgsConstructor(lombok.AllArgsConstructor) HashMap(java.util.HashMap) ToString(lombok.ToString) Function(org.apache.pulsar.functions.proto.Function) HashSet(java.util.HashSet) LinkedList(java.util.LinkedList) HashMap(java.util.HashMap) Map(java.util.Map)

Example 2 with Function

use of org.apache.pulsar.functions.proto.Function in project incubator-pulsar by apache.

the class FunctionActioner method stopFunction.

private void stopFunction(FunctionRuntimeInfo functionRuntimeInfo) {
    Function.Instance instance = functionRuntimeInfo.getFunctionInstance();
    FunctionMetaData functionMetaData = instance.getFunctionMetaData();
    log.info("Stopping function {} - {}...", functionMetaData.getFunctionConfig().getName(), instance.getInstanceId());
    if (functionRuntimeInfo.getRuntimeSpawner() != null) {
        functionRuntimeInfo.getRuntimeSpawner().close();
        functionRuntimeInfo.setRuntimeSpawner(null);
    }
    // clean up function package
    File pkgDir = new File(workerConfig.getDownloadDirectory(), getDownloadPackagePath(functionMetaData));
    if (pkgDir.exists()) {
        try {
            FileUtils.deleteDirectory(pkgDir);
        } catch (IOException e) {
            log.warn("Failed to delete package for function: {}", FunctionConfigUtils.getFullyQualifiedName(functionMetaData.getFunctionConfig()), e);
        }
    }
}
Also used : FunctionMetaData(org.apache.pulsar.functions.proto.Function.FunctionMetaData) Function(org.apache.pulsar.functions.proto.Function) IOException(java.io.IOException) File(java.io.File)

Example 3 with Function

use of org.apache.pulsar.functions.proto.Function in project incubator-pulsar by apache.

the class FunctionActioner method startFunction.

private void startFunction(FunctionRuntimeInfo functionRuntimeInfo) throws Exception {
    Function.Instance instance = functionRuntimeInfo.getFunctionInstance();
    FunctionMetaData functionMetaData = instance.getFunctionMetaData();
    log.info("Starting function {} - {} ...", functionMetaData.getFunctionConfig().getName(), instance.getInstanceId());
    File pkgDir = new File(workerConfig.getDownloadDirectory(), getDownloadPackagePath(functionMetaData));
    pkgDir.mkdirs();
    int instanceId = functionRuntimeInfo.getFunctionInstance().getInstanceId();
    File pkgFile = new File(pkgDir, new File(FunctionConfigUtils.getDownloadFileName(functionMetaData.getFunctionConfig())).getName());
    if (!pkgFile.exists()) {
        // download only when the package file doesn't exist
        File tempPkgFile;
        while (true) {
            tempPkgFile = new File(pkgDir, pkgFile.getName() + "." + instanceId + "." + UUID.randomUUID().toString());
            if (!tempPkgFile.exists() && tempPkgFile.createNewFile()) {
                break;
            }
        }
        try {
            log.info("Function package file {} will be downloaded from {}", tempPkgFile, functionMetaData.getPackageLocation());
            Utils.downloadFromBookkeeper(dlogNamespace, new FileOutputStream(tempPkgFile), functionMetaData.getPackageLocation().getPackagePath());
            // this ensures one instance will successfully download the package.
            try {
                Files.createLink(Paths.get(pkgFile.toURI()), Paths.get(tempPkgFile.toURI()));
                log.info("Function package file is linked from {} to {}", tempPkgFile, pkgFile);
            } catch (FileAlreadyExistsException faee) {
                // file already exists
                log.warn("Function package has been downloaded from {} and saved at {}", functionMetaData.getPackageLocation(), pkgFile);
            }
        } finally {
            tempPkgFile.delete();
        }
    }
    InstanceConfig instanceConfig = new InstanceConfig();
    instanceConfig.setFunctionConfig(functionMetaData.getFunctionConfig());
    // TODO: set correct function id and version when features implemented
    instanceConfig.setFunctionId(UUID.randomUUID().toString());
    instanceConfig.setFunctionVersion(UUID.randomUUID().toString());
    instanceConfig.setInstanceId(String.valueOf(instanceId));
    instanceConfig.setMaxBufferedTuples(1024);
    RuntimeSpawner runtimeSpawner = new RuntimeSpawner(instanceConfig, pkgFile.getAbsolutePath(), runtimeFactory, workerConfig.getInstanceLivenessCheckFreqMs());
    functionRuntimeInfo.setRuntimeSpawner(runtimeSpawner);
    runtimeSpawner.start();
}
Also used : FunctionMetaData(org.apache.pulsar.functions.proto.Function.FunctionMetaData) Function(org.apache.pulsar.functions.proto.Function) FileAlreadyExistsException(java.nio.file.FileAlreadyExistsException) InstanceConfig(org.apache.pulsar.functions.instance.InstanceConfig) FileOutputStream(java.io.FileOutputStream) File(java.io.File) RuntimeSpawner(org.apache.pulsar.functions.runtime.RuntimeSpawner)

Example 4 with Function

use of org.apache.pulsar.functions.proto.Function in project incubator-pulsar by apache.

the class SchedulerManager method invokeScheduler.

private void invokeScheduler() {
    List<String> currentMembership = this.membershipManager.getCurrentMembership().stream().map(workerInfo -> workerInfo.getWorkerId()).collect(Collectors.toList());
    List<FunctionMetaData> allFunctions = this.functionMetaDataManager.getAllFunctionMetaData();
    Map<String, Function.Instance> allInstances = computeAllInstances(allFunctions);
    Map<String, Map<String, Assignment>> workerIdToAssignments = this.functionRuntimeManager.getCurrentAssignments();
    // delete assignments of functions and instances that don't exist anymore
    Iterator<Map.Entry<String, Map<String, Assignment>>> it = workerIdToAssignments.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<String, Map<String, Assignment>> workerIdToAssignmentEntry = it.next();
        Map<String, Assignment> functionMap = workerIdToAssignmentEntry.getValue();
        // remove instances that don't exist anymore
        functionMap.entrySet().removeIf(entry -> {
            String fullyQualifiedInstanceId = entry.getKey();
            return !allInstances.containsKey(fullyQualifiedInstanceId);
        });
        // update assignment instances in case attributes of a function gets updated
        for (Map.Entry<String, Assignment> entry : functionMap.entrySet()) {
            String fullyQualifiedInstanceId = entry.getKey();
            Assignment assignment = entry.getValue();
            Function.Instance instance = allInstances.get(fullyQualifiedInstanceId);
            if (!assignment.getInstance().equals(instance)) {
                functionMap.put(fullyQualifiedInstanceId, assignment.toBuilder().setInstance(instance).build());
            }
        }
        if (functionMap.isEmpty()) {
            it.remove();
        }
    }
    List<Assignment> currentAssignments = workerIdToAssignments.entrySet().stream().flatMap(stringMapEntry -> stringMapEntry.getValue().values().stream()).collect(Collectors.toList());
    List<Function.Instance> needsAssignment = this.getUnassignedFunctionInstances(workerIdToAssignments, allInstances);
    List<Assignment> assignments = this.scheduler.schedule(needsAssignment, currentAssignments, currentMembership);
    log.debug("New assignments computed: {}", assignments);
    long assignmentVersion = this.functionRuntimeManager.getCurrentAssignmentVersion() + 1;
    Request.AssignmentsUpdate assignmentsUpdate = Request.AssignmentsUpdate.newBuilder().setVersion(assignmentVersion).addAllAssignments(assignments).build();
    CompletableFuture<MessageId> messageIdCompletableFuture = producer.sendAsync(assignmentsUpdate.toByteArray());
    try {
        messageIdCompletableFuture.get();
    } catch (InterruptedException | ExecutionException e) {
        log.error("Failed to send assignment update", e);
        throw new RuntimeException(e);
    }
    // wait for assignment update to go throw the pipeline
    int retries = 0;
    while (this.functionRuntimeManager.getCurrentAssignmentVersion() < assignmentVersion) {
        if (retries >= this.workerConfig.getAssignmentWriteMaxRetries()) {
            log.warn("Max number of retries reached for waiting for assignment to propagate. Will continue now.");
            break;
        }
        log.info("Waiting for assignments to propagate...");
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        retries++;
    }
}
Also used : Setter(lombok.Setter) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) Request(org.apache.pulsar.functions.proto.Request) Producer(org.apache.pulsar.client.api.Producer) FunctionMetaData(org.apache.pulsar.functions.proto.Function.FunctionMetaData) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) Future(java.util.concurrent.Future) Map(java.util.Map) PulsarClient(org.apache.pulsar.client.api.PulsarClient) LinkedList(java.util.LinkedList) PulsarClientException(org.apache.pulsar.client.api.PulsarClientException) ExecutorService(java.util.concurrent.ExecutorService) Function(org.apache.pulsar.functions.proto.Function) Iterator(java.util.Iterator) CompressionType(org.apache.pulsar.client.api.CompressionType) Reflections(org.apache.pulsar.functions.utils.Reflections) Assignment(org.apache.pulsar.functions.proto.Function.Assignment) ProducerConfiguration(org.apache.pulsar.client.api.ProducerConfiguration) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Collectors(java.util.stream.Collectors) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Slf4j(lombok.extern.slf4j.Slf4j) List(java.util.List) MessageId(org.apache.pulsar.client.api.MessageId) IScheduler(org.apache.pulsar.functions.worker.scheduler.IScheduler) FunctionMetaData(org.apache.pulsar.functions.proto.Function.FunctionMetaData) Assignment(org.apache.pulsar.functions.proto.Function.Assignment) Function(org.apache.pulsar.functions.proto.Function) ExecutionException(java.util.concurrent.ExecutionException) Request(org.apache.pulsar.functions.proto.Request) HashMap(java.util.HashMap) Map(java.util.Map) MessageId(org.apache.pulsar.client.api.MessageId)

Aggregations

Function (org.apache.pulsar.functions.proto.Function)4 FunctionMetaData (org.apache.pulsar.functions.proto.Function.FunctionMetaData)3 File (java.io.File)2 HashMap (java.util.HashMap)2 Iterator (java.util.Iterator)2 LinkedList (java.util.LinkedList)2 List (java.util.List)2 Map (java.util.Map)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 Collectors (java.util.stream.Collectors)2 Slf4j (lombok.extern.slf4j.Slf4j)2 PulsarClient (org.apache.pulsar.client.api.PulsarClient)2 PulsarClientException (org.apache.pulsar.client.api.PulsarClientException)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 FileAlreadyExistsException (java.nio.file.FileAlreadyExistsException)1 Collection (java.util.Collection)1 HashSet (java.util.HashSet)1 Set (java.util.Set)1