Hi @Bishal072 ,
Problem Summary
After upgrading from Camunda 8.7 to 8.8/8.9, DEADLINE_EXCEEDED errors occur frequently when debugging Java worker/client code locally using c8run. This happens especially when breakpoints pause execution, making debugging sessions barely last 30 minutes.
Root Cause
In Camunda 8.8+, several timeout defaults were tightened and the gRPC gateway behavior changed:
-
Zeebe Gateway request timeout was reduced in newer versions
-
Job worker lock duration defaults are shorter
-
gRPC keep-alive and deadline settings are more aggressive
-
Long poll timeout for job workers can conflict with breakpoint pauses
When you hit a breakpoint, the JVM pauses entirely — including the job worker’s internal threads that handle heartbeats, polling, and gRPC stream management. This causes the gateway to consider the connection dead and return DEADLINE_EXCEEDED.
Solution 1: Increase Java Client Timeouts (Recommended)
Zeebe Client Configuration
import io.camunda.zeebe.client.ZeebeClient;
import java.time.Duration;
ZeebeClient client = ZeebeClient.newClientBuilder()
.gatewayAddress("localhost:26500")
.usePlaintext()
// Increase the default request timeout (default is 20s in 8.8+)
.defaultRequestTimeout(Duration.ofMinutes(10))
// Increase gRPC message size if needed
.maxMessageSize(4 * 1024 * 1024)
.build();
Job Worker Configuration
import io.camunda.zeebe.client.api.worker.JobWorker;
import java.time.Duration;
JobWorker worker = client.newWorkerBuilder()
.jobType("my-job-type")
.handler(jobHandler)
// Increase job timeout so Zeebe won't reassign while you're on a breakpoint
.timeout(Duration.ofMinutes(30))
// Increase poll interval to reduce frequency of deadline-sensitive calls
.pollInterval(Duration.ofSeconds(30))
// Request fewer jobs at a time during debugging
.maxJobsActive(1)
// Increase request timeout for this worker
.requestTimeout(Duration.ofMinutes(10))
.open();
Spring Boot / application.yaml Configuration
If using Spring Boot with Camunda 8 starter:
camunda:
client:
zeebe:
defaults:
request-timeout: PT10M
override:
request-timeout: PT10M
worker:
defaults:
timeout: PT30M
poll-interval: PT30S
request-timeout: PT10M
override:
timeout: PT30M
zeebe:
client:
broker:
gatewayAddress: localhost:26500
security:
plaintext: true
requestTimeout: PT10M
worker:
defaultJobTimeout: PT30M
defaultJobWorkerMaxJobsActive: 1
defaultJobPollInterval: PT30S
application.properties Alternative
# Zeebe client timeout settings for debugging
camunda.client.zeebe.defaults.request-timeout=PT10M
camunda.client.worker.defaults.timeout=PT30M
camunda.client.worker.defaults.poll-interval=PT30S
camunda.client.worker.defaults.request-timeout=PT10M
# Legacy property names (for older Spring starters)
zeebe.client.requestTimeout=600000
zeebe.client.worker.defaultJobTimeout=1800000
zeebe.client.worker.defaultJobWorkerMaxJobsActive=1
Solution 2: Configure c8run Gateway Timeouts
Modify Zeebe Gateway Configuration
Locate or create a configuration file for your c8run instance. Typically you can set environment variables or modify application.yaml in the c8run directory.
Environment Variables (set before running c8run)
REM Windows cmd.exe
set ZEEBE_GATEWAY_LONGPOLLING_TIMEOUT=600000
set ZEEBE_GATEWAY_REQUEST_TIMEOUT=600s
set ZEEBE_BROKER_GATEWAY_LONGPOLLING_TIMEOUT=600000
set ZEEBE_GATEWAY_GRPC_MAXMESSAGESIZE=4194304
set ZEEBE_GATEWAY_KEEPALIVE_INTERVAL=300s
c8run.exe start
# PowerShell
$env:ZEEBE_GATEWAY_LONGPOLLING_TIMEOUT = "600000"
$env:ZEEBE_GATEWAY_REQUEST_TIMEOUT = "600s"
$env:ZEEBE_BROKER_GATEWAY_LONGPOLLING_TIMEOUT = "600000"
$env:ZEEBE_GATEWAY_GRPC_MAXMESSAGESIZE = "4194304"
$env:ZEEBE_GATEWAY_KEEPALIVE_INTERVAL = "300s"
.\c8run.exe start
c8run YAML Configuration Override
If c8run supports a custom config file (check your version’s docs), create or modify config/application.yaml:
zeebe:
gateway:
longPolling:
timeout: 600000 # 10 minutes in ms
request:
timeout: 600s
grpc:
maxMessageSize: 4MB
keepAlive:
interval: 300s
broker:
gateway:
longPolling:
timeout: 600000
Solution 3: Create a Debug-Specific Profile
Create a separate Spring profile for debugging that maximizes all timeouts:
application-debug.yaml
camunda:
client:
zeebe:
defaults:
request-timeout: PT30M
override:
request-timeout: PT30M
worker:
defaults:
timeout: PT60M
poll-interval: PT60S
request-timeout: PT30M
max-jobs-active: 1
override:
timeout: PT60M
logging:
level:
io.camunda: DEBUG
io.grpc: DEBUG
Run with:
java -Dspring.profiles.active=debug -jar your-app.jar
Or in your IDE run configuration, add VM argument: -Dspring.profiles.active=debug
Solution 4: gRPC Channel Configuration (Advanced)
For fine-grained control over gRPC behavior:
import io.camunda.zeebe.client.ZeebeClient;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
// Build a custom gRPC channel with relaxed timeouts
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 26500)
.usePlaintext()
.keepAliveTime(5, TimeUnit.MINUTES)
.keepAliveTimeout(10, TimeUnit.MINUTES)
.keepAliveWithoutCalls(true)
.idleTimeout(60, TimeUnit.MINUTES)
.maxInboundMessageSize(4 * 1024 * 1024)
.build();
// Use the custom channel (if your client version supports it)
ZeebeClient client = ZeebeClient.newClientBuilder()
.gatewayAddress("localhost:26500")
.usePlaintext()
.defaultRequestTimeout(Duration.ofMinutes(30))
.build();
Solution 5: Job Completion Pattern for Debugging
Instead of having the worker auto-complete the job inside the handler (which times out while you’re on a breakpoint), consider a manual completion pattern:
import io.camunda.zeebe.client.api.response.ActivatedJob;
import io.camunda.zeebe.client.api.worker.JobClient;
import io.camunda.zeebe.client.api.worker.JobHandler;
public class DebugFriendlyHandler implements JobHandler {
@Override
public void handle(JobClient client, ActivatedJob job) throws Exception {
// Set a very long deadline for this specific job completion
// This gives you time to step through with breakpoints
System.out.println("Processing job: " + job.getKey());
System.out.println("Variables: " + job.getVariables());
// Your business logic here - set breakpoints below this line
Object result = doBusinessLogic(job);
// Complete with extended timeout
client.newCompleteCommand(job.getKey())
.variables(Map.of("result", result))
.requestTimeout(Duration.ofMinutes(10))
.send()
.join();
}
private Object doBusinessLogic(ActivatedJob job) {
// <-- Set your breakpoints here
return "processed";
}
}
Solution 6: Workaround — Use StreamEnabled=false
Camunda 8.8+ introduced streaming for job workers by default. Disabling it can help with debugging:
JobWorker worker = client.newWorkerBuilder()
.jobType("my-job-type")
.handler(jobHandler)
.timeout(Duration.ofMinutes(30))
.streamEnabled(false) // Disable streaming, use polling only
.pollInterval(Duration.ofSeconds(30))
.maxJobsActive(1)
.requestTimeout(Duration.ofMinutes(10))
.open();
Spring Boot:
camunda:
client:
worker:
defaults:
stream-enabled: false
timeout: PT30M
poll-interval: PT30S
Key Differences: Camunda 8.7 vs 8.8/8.9
| Setting |
8.7 Default |
8.8/8.9 Default |
Impact on Debugging |
| Gateway request timeout |
30s+ |
20s |
Shorter window before DEADLINE_EXCEEDED |
| Job worker streaming |
Not default |
Enabled by default |
Streams break when JVM pauses |
| Long poll timeout |
Generous |
Tighter |
Polls expire during breakpoint pauses |
| gRPC keep-alive |
Relaxed |
More aggressive |
Connections dropped sooner |
| Default job timeout |
5 min |
5 min (but reassignment faster) |
Jobs reassigned while debugging |
Recommended Debugging Workflow
-
Start c8run with extended timeouts (Solution 2)
-
Use a debug Spring profile (Solution 3) with:
-
Set breakpoints only in business logic, not in framework/handler infrastructure code
-
Use conditional breakpoints to minimize pause frequency
-
If debugging a specific process instance, activate a single job manually rather than using continuous polling:
// Manual single-job activation for focused debugging
ActivateJobsResponse response = client.newActivateJobsCommand()
.jobType("my-job-type")
.maxJobsToActivate(1)
.timeout(Duration.ofMinutes(60)) // Very long timeout for debugging
.requestTimeout(Duration.ofMinutes(10))
.send()
.join();
for (ActivatedJob job : response.getJobs()) {
// Set breakpoint here
processJob(job);
client.newCompleteCommand(job.getKey())
.requestTimeout(Duration.ofMinutes(10))
.send()
.join();
}
Quick-Start Fix (Minimal Changes)
If you want the fastest fix with minimal code changes, add these JVM arguments to your IDE debug configuration:
-Dzeebe.client.requestTimeout=600000
-Dzeebe.client.worker.defaultJobTimeout=1800000
-Dzeebe.client.worker.defaultJobWorkerMaxJobsActive=1
-Dcamunda.client.zeebe.defaults.request-timeout=PT10M
-Dcamunda.client.worker.defaults.timeout=PT30M
-Dcamunda.client.worker.defaults.stream-enabled=false
And set these environment variables before starting c8run:
set ZEEBE_GATEWAY_LONGPOLLING_TIMEOUT=600000
set ZEEBE_GATEWAY_REQUEST_TIMEOUT=600s
c8run.exe start