{"record":{"id":"690d25a6ed60df0b","repo":"apache/pulsar","slug":"externally-managed-schedulers-can-t-do-per-instanc","errorCode":null,"errorMessage":"Externally managed schedulers can't do per instance stop","messagePattern":"Externally managed schedulers can't do per instance stop","errorType":"http","errorClass":"WebApplicationException","httpStatus":501,"severity":"error","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/FunctionRuntimeManager.java","lineNumber":363,"sourceCode":"\n        return assignments;\n    }\n\n    /**\n     * Removes a collection of assignments.\n     *\n     * @param assignments assignments to remove\n     */\n    public synchronized void removeAssignments(Collection<Assignment> assignments) {\n        for (Assignment assignment : assignments) {\n            this.deleteAssignment(assignment);\n        }\n    }\n\n    public synchronized void restartFunctionInstance(String tenant, String namespace,\n                                                     String functionName, int instanceId, URI uri) throws Exception {\n        if (runtimeFactory.externallyManaged()) {\n            throw new WebApplicationException(Response.serverError().status(Status.NOT_IMPLEMENTED)\n                    .type(MediaType.APPLICATION_JSON)\n                    .entity(new ErrorData(\"Externally managed schedulers can't do per instance stop\")).build());\n        }\n        Assignment assignment = this.findAssignment(tenant, namespace, functionName, instanceId);\n        final String fullFunctionName = String.format(\"%s/%s/%s/%s\", tenant, namespace, functionName, instanceId);\n        if (assignment == null) {\n            throw new WebApplicationException(Response.serverError().status(Status.BAD_REQUEST)\n                    .type(MediaType.APPLICATION_JSON)\n                    .entity(new ErrorData(fullFunctionName + \" doesn't exist\")).build());\n        }\n\n        final String assignedWorkerId = assignment.getWorkerId();\n        final String workerId = this.workerConfig.getWorkerId();\n\n        if (assignedWorkerId.equals(workerId)) {\n            stopFunction(FunctionCommon.getFullyQualifiedInstanceId(assignment.getInstance()), true);\n            return;\n        } else {","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/FunctionRuntimeManager.java#L345-L381","documentation":"FunctionRuntimeManager.restartFunctionInstance refuses to restart a single function instance when the runtime factory is externally managed (e.g. Kubernetes). With external schedulers, instance placement/restarts belong to the external scheduler, so the manager answers HTTP 505/501-style NOT_IMPLEMENTED wrapped in a WebApplicationException with the message 'Externally managed schedulers can't do per instance stop'.","triggerScenarios":"Calling the per-instance restart admin API (restartFunctionInstance with a specific instanceId) against a worker whose function runtime factory is externally managed (runtimeFactory.externallyManaged() == true, e.g. kubernetes runtime).","commonSituations":"Running Pulsar Functions on Kubernetes but calling the standalone-runtime per-instance restart REST endpoint; automation/scripts written for thread/process runtime being reused on a K8s deployment; admin UI invoking per-instance restart buttons on an externally managed cluster.","solutions":["Restart the whole function instead of a single instance (restartFunctionInstances / restart all instances endpoint).","Delete/restart the individual Kubernetes pod backing the instance (kubectl delete pod <instance-pod>) — the external scheduler owns instance lifecycle.","Switch the worker's function runtime factory to process/thread mode if you truly need per-instance control (not usually desirable in production).","Handle the 501 NOT_IMPLEMENTED response in client code and fall back to full-function restart."],"exampleFix":"// before\nadmin.functions().restartFunctionInstance(tenant, namespace, functionName, instanceId);\n// after\ntry {\n    admin.functions().restartFunctionInstance(tenant, namespace, functionName, instanceId);\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 501) {\n        // externally managed: restart all instances instead\n        admin.functions().restartFunction(tenant, namespace, functionName);\n    } else {\n        throw e;\n    }\n}","handlingStrategy":"validation","validationCode":"FunctionRuntimeInfo rt = admin.functions().getRuntimeInfo(tenant, ns, fn);\n// externally managed (K8s) deployments do not support per-instance restart;\n// fall back to full-function restart instead of calling restartFunctionInstance","typeGuard":null,"tryCatchPattern":"try {\n    admin.functions().restartFunctionInstance(tenant, ns, fn, instanceId);\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 501) {\n        admin.functions().restartFunction(tenant, ns, fn);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Detect externally managed runtime (Kubernetes) up front and use whole-function restart APIs.","Manage instance restarts with kubectl/cluster tooling when runtimeFactory is externally managed.","Avoid copy-pasting standalone-runtime admin scripts onto K8s deployments."],"tags":["pulsar-functions","kubernetes","unsupported-operation"],"backgroundTag":"operation-not-supported-on-runtime","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}