This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 66d37e8b3887 CAMEL-24525: camel-google-firestore - bound the realtime
change buffer
66d37e8b3887 is described below
commit 66d37e8b3887314331d7c853d37142757f9eaa18
Author: Andrea Cosentino <[email protected]>
AuthorDate: Sun Aug 30 13:48:24 2026 +0200
CAMEL-24525: camel-google-firestore - bound the realtime change buffer
GoogleFirestoreConsumer buffered document changes reported by the snapshot
listener in an unbounded queue and drained it on the scheduled poll. The
listener callback runs on a Firestore client thread and is never throttled
by the route, so a collection changing faster than the route consumes it
made the buffer grow without limit, holding full Exchange objects. It also
kept growing while the route was suspended.
A new maxPendingChanges consumer option bounds the buffer. The default is
unbounded, so existing routes are unaffected. When a limit is reached, the
oldest buffered change is discarded and a warning logged, leaving the route
with the most recent state. Blocking the listener thread was deliberately
not offered, since it belongs to the Firestore gRPC client and would stall
the watch stream. The buffer is now a LinkedBlockingQueue for O(1) size and
drainTo support.
Closes #25898
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.../camel/catalog/components/google-firestore.json | 50 +++++-----
.../catalog/docs/google-firestore-component.adoc | 12 +++
.../GoogleFirestoreComponentConfigurer.java | 6 ++
.../GoogleFirestoreEndpointConfigurer.java | 6 ++
.../GoogleFirestoreEndpointUriFactory.java | 3 +-
.../google/firestore/google-firestore.json | 50 +++++-----
.../src/main/docs/google-firestore-component.adoc | 12 +++
.../firestore/GoogleFirestoreConfiguration.java | 22 +++++
.../google/firestore/GoogleFirestoreConsumer.java | 68 +++++++++++--
.../GoogleFirestoreConsumerBufferTest.java | 106 +++++++++++++++++++++
.../GoogleFirestoreComponentBuilderFactory.java | 22 +++++
.../dsl/GoogleFirestoreEndpointBuilderFactory.java | 42 ++++++++
12 files changed, 342 insertions(+), 57 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/google-firestore.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/google-firestore.json
index 11f9b15d2195..05587d088f63 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/google-firestore.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/google-firestore.json
@@ -31,12 +31,13 @@
"serviceAccountKey": { "index": 4, "kind": "property", "displayName":
"Service Account Key", "group": "common", "label": "common", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The Service account key
that can be used as credentials for the Firestore cli [...]
"bridgeErrorHandler": { "index": 5, "kind": "property", "displayName":
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Allows for bridging the consumer to the Camel routing Error Handler, which
mean any exceptions (if possible) occurred while the Camel consumer is trying
to pickup incoming messages, or the like [...]
"realtimeUpdates": { "index": 6, "kind": "property", "displayName":
"Realtime Updates", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false,
"configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "When true, the consumer
will listen for real-time updates on th [...]
- "documentId": { "index": 7, "kind": "property", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
- "lazyStartProducer": { "index": 8, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
- "operation": { "index": 9, "kind": "property", "displayName": "Operation",
"group": "producer", "label": "producer", "required": false, "type": "enum",
"javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.came [...]
- "autowiredEnabled": { "index": 10, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
- "healthCheckConsumerEnabled": { "index": 11, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
- "healthCheckProducerEnabled": { "index": 12, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "maxPendingChanges": { "index": 7, "kind": "property", "displayName": "Max
Pending Changes", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 0, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "Maximum number of
realtime document changes bu [...]
+ "documentId": { "index": 8, "kind": "property", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
+ "lazyStartProducer": { "index": 9, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
+ "operation": { "index": 10, "kind": "property", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.cam [...]
+ "autowiredEnabled": { "index": 11, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
+ "healthCheckConsumerEnabled": { "index": 12, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
+ "healthCheckProducerEnabled": { "index": 13, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
},
"headers": {
"CamelGoogleFirestoreOperation": { "index": 0, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The op [...]
@@ -67,23 +68,24 @@
"bridgeErrorHandler": { "index": 7, "kind": "parameter", "displayName":
"Bridge Error Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Allows for bridging the consumer to the
Camel routing Error Handler, which mean any exceptions (if possible) occurred
while the Camel consumer is trying to pickup incoming [...]
"exceptionHandler": { "index": 8, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By def [...]
"exchangePattern": { "index": 9, "kind": "parameter", "displayName":
"Exchange Pattern", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "enum", "javaType":
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ],
"deprecated": false, "autowired": false, "secret": false, "description": "Sets
the exchange pattern when the consumer creates an exchange." },
- "pollStrategy": { "index": 10, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
- "documentId": { "index": 11, "kind": "parameter", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
- "operation": { "index": 12, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.ca [...]
- "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
- "backoffErrorThreshold": { "index": 14, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
- "backoffIdleThreshold": { "index": 15, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
- "backoffMultiplier": { "index": 16, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
- "delay": { "index": 17, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
- "greedy": { "index": 18, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
- "initialDelay": { "index": 19, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
- "repeatCount": { "index": 20, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
- "runLoggingLevel": { "index": 21, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
- "scheduledExecutorService": { "index": 22, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
- "scheduler": { "index": 23, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
- "schedulerProperties": { "index": 24, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
- "startScheduler": { "index": 25, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
- "timeUnit": { "index": 26, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
- "useFixedDelay": { "index": 27, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." }
+ "maxPendingChanges": { "index": 10, "kind": "parameter", "displayName":
"Max Pending Changes", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 0,
"configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "Maximum number of
realtime document changes [...]
+ "pollStrategy": { "index": 11, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
+ "documentId": { "index": 12, "kind": "parameter", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
+ "operation": { "index": 13, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.ca [...]
+ "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "backoffErrorThreshold": { "index": 15, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
+ "backoffIdleThreshold": { "index": 16, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
+ "backoffMultiplier": { "index": 17, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
+ "delay": { "index": 18, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
+ "greedy": { "index": 19, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
+ "initialDelay": { "index": 20, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
+ "repeatCount": { "index": 21, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
+ "runLoggingLevel": { "index": 22, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
+ "scheduledExecutorService": { "index": 23, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
+ "scheduler": { "index": 24, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
+ "schedulerProperties": { "index": 25, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
+ "startScheduler": { "index": 26, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
+ "timeUnit": { "index": 27, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
+ "useFixedDelay": { "index": 28, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." }
}
}
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-firestore-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-firestore-component.adoc
index 3fc57d7b5684..62929b4ed958 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-firestore-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-firestore-component.adoc
@@ -243,6 +243,18 @@ YAML::
----
====
+In real-time mode the document changes reported by the listener are buffered
until the next poll picks them up. That
+buffer is unbounded by default, so a collection changing faster than the route
consumes it makes the buffer grow, and
+it keeps growing while the route is suspended. Set `maxPendingChanges` to
bound it: when the buffer is full the oldest
+buffered change is discarded and a warning is logged, which leaves the route
with the most recent state of the
+collection.
+
+[source,java]
+----
+from("google-firestore://myCollection?realtimeUpdates=true&maxPendingChanges=1000")
+ .to("log:changes");
+----
+
=== Advanced Component Configuration
If you need more control over the `Firestore` client instance configuration,
you can create your own instance and refer to it in your Camel google-firestore
component configuration:
diff --git
a/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreComponentConfigurer.java
b/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreComponentConfigurer.java
index c4316878327a..155cfd20a31e 100644
---
a/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreComponentConfigurer.java
+++
b/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreComponentConfigurer.java
@@ -47,6 +47,8 @@ public class GoogleFirestoreComponentConfigurer extends
PropertyConfigurerSuppor
case "healthCheckProducerEnabled":
target.setHealthCheckProducerEnabled(property(camelContext, boolean.class,
value)); return true;
case "lazystartproducer":
case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
+ case "maxpendingchanges":
+ case "maxPendingChanges":
getOrCreateConfiguration(target).setMaxPendingChanges(property(camelContext,
int.class, value)); return true;
case "operation":
getOrCreateConfiguration(target).setOperation(property(camelContext,
org.apache.camel.component.google.firestore.GoogleFirestoreOperations.class,
value)); return true;
case "projectid":
case "projectId":
getOrCreateConfiguration(target).setProjectId(property(camelContext,
java.lang.String.class, value)); return true;
@@ -83,6 +85,8 @@ public class GoogleFirestoreComponentConfigurer extends
PropertyConfigurerSuppor
case "healthCheckProducerEnabled": return boolean.class;
case "lazystartproducer":
case "lazyStartProducer": return boolean.class;
+ case "maxpendingchanges":
+ case "maxPendingChanges": return int.class;
case "operation": return
org.apache.camel.component.google.firestore.GoogleFirestoreOperations.class;
case "projectid":
case "projectId": return java.lang.String.class;
@@ -115,6 +119,8 @@ public class GoogleFirestoreComponentConfigurer extends
PropertyConfigurerSuppor
case "healthCheckProducerEnabled": return
target.isHealthCheckProducerEnabled();
case "lazystartproducer":
case "lazyStartProducer": return target.isLazyStartProducer();
+ case "maxpendingchanges":
+ case "maxPendingChanges": return
getOrCreateConfiguration(target).getMaxPendingChanges();
case "operation": return
getOrCreateConfiguration(target).getOperation();
case "projectid":
case "projectId": return
getOrCreateConfiguration(target).getProjectId();
diff --git
a/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointConfigurer.java
b/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointConfigurer.java
index f20599581ce5..dee730d2bb51 100644
---
a/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointConfigurer.java
+++
b/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointConfigurer.java
@@ -47,6 +47,8 @@ public class GoogleFirestoreEndpointConfigurer extends
PropertyConfigurerSupport
case "initialDelay": target.setInitialDelay(property(camelContext,
long.class, value)); return true;
case "lazystartproducer":
case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
+ case "maxpendingchanges":
+ case "maxPendingChanges":
target.getConfiguration().setMaxPendingChanges(property(camelContext,
int.class, value)); return true;
case "operation":
target.getConfiguration().setOperation(property(camelContext,
org.apache.camel.component.google.firestore.GoogleFirestoreOperations.class,
value)); return true;
case "pollstrategy":
case "pollStrategy": target.setPollStrategy(property(camelContext,
org.apache.camel.spi.PollingConsumerPollStrategy.class, value)); return true;
@@ -109,6 +111,8 @@ public class GoogleFirestoreEndpointConfigurer extends
PropertyConfigurerSupport
case "initialDelay": return long.class;
case "lazystartproducer":
case "lazyStartProducer": return boolean.class;
+ case "maxpendingchanges":
+ case "maxPendingChanges": return int.class;
case "operation": return
org.apache.camel.component.google.firestore.GoogleFirestoreOperations.class;
case "pollstrategy":
case "pollStrategy": return
org.apache.camel.spi.PollingConsumerPollStrategy.class;
@@ -167,6 +171,8 @@ public class GoogleFirestoreEndpointConfigurer extends
PropertyConfigurerSupport
case "initialDelay": return target.getInitialDelay();
case "lazystartproducer":
case "lazyStartProducer": return target.isLazyStartProducer();
+ case "maxpendingchanges":
+ case "maxPendingChanges": return
target.getConfiguration().getMaxPendingChanges();
case "operation": return target.getConfiguration().getOperation();
case "pollstrategy":
case "pollStrategy": return target.getPollStrategy();
diff --git
a/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointUriFactory.java
b/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointUriFactory.java
index e5cdd9aae03d..8be0b19e24b1 100644
---
a/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointUriFactory.java
+++
b/components/camel-google/camel-google-firestore/src/generated/java/org/apache/camel/component/google/firestore/GoogleFirestoreEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class GoogleFirestoreEndpointUriFactory extends
org.apache.camel.support.
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(28);
+ Set<String> props = new HashSet<>(29);
props.add("backoffErrorThreshold");
props.add("backoffIdleThreshold");
props.add("backoffMultiplier");
@@ -39,6 +39,7 @@ public class GoogleFirestoreEndpointUriFactory extends
org.apache.camel.support.
props.add("greedy");
props.add("initialDelay");
props.add("lazyStartProducer");
+ props.add("maxPendingChanges");
props.add("operation");
props.add("pollStrategy");
props.add("projectId");
diff --git
a/components/camel-google/camel-google-firestore/src/generated/resources/META-INF/org/apache/camel/component/google/firestore/google-firestore.json
b/components/camel-google/camel-google-firestore/src/generated/resources/META-INF/org/apache/camel/component/google/firestore/google-firestore.json
index 11f9b15d2195..05587d088f63 100644
---
a/components/camel-google/camel-google-firestore/src/generated/resources/META-INF/org/apache/camel/component/google/firestore/google-firestore.json
+++
b/components/camel-google/camel-google-firestore/src/generated/resources/META-INF/org/apache/camel/component/google/firestore/google-firestore.json
@@ -31,12 +31,13 @@
"serviceAccountKey": { "index": 4, "kind": "property", "displayName":
"Service Account Key", "group": "common", "label": "common", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The Service account key
that can be used as credentials for the Firestore cli [...]
"bridgeErrorHandler": { "index": 5, "kind": "property", "displayName":
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Allows for bridging the consumer to the Camel routing Error Handler, which
mean any exceptions (if possible) occurred while the Camel consumer is trying
to pickup incoming messages, or the like [...]
"realtimeUpdates": { "index": 6, "kind": "property", "displayName":
"Realtime Updates", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false,
"configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "When true, the consumer
will listen for real-time updates on th [...]
- "documentId": { "index": 7, "kind": "property", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
- "lazyStartProducer": { "index": 8, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
- "operation": { "index": 9, "kind": "property", "displayName": "Operation",
"group": "producer", "label": "producer", "required": false, "type": "enum",
"javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.came [...]
- "autowiredEnabled": { "index": 10, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
- "healthCheckConsumerEnabled": { "index": 11, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
- "healthCheckProducerEnabled": { "index": 12, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "maxPendingChanges": { "index": 7, "kind": "property", "displayName": "Max
Pending Changes", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 0, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "Maximum number of
realtime document changes bu [...]
+ "documentId": { "index": 8, "kind": "property", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
+ "lazyStartProducer": { "index": 9, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
+ "operation": { "index": 10, "kind": "property", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.cam [...]
+ "autowiredEnabled": { "index": 11, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
+ "healthCheckConsumerEnabled": { "index": 12, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
+ "healthCheckProducerEnabled": { "index": 13, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
},
"headers": {
"CamelGoogleFirestoreOperation": { "index": 0, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "description": "The op [...]
@@ -67,23 +68,24 @@
"bridgeErrorHandler": { "index": 7, "kind": "parameter", "displayName":
"Bridge Error Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Allows for bridging the consumer to the
Camel routing Error Handler, which mean any exceptions (if possible) occurred
while the Camel consumer is trying to pickup incoming [...]
"exceptionHandler": { "index": 8, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By def [...]
"exchangePattern": { "index": 9, "kind": "parameter", "displayName":
"Exchange Pattern", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "enum", "javaType":
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ],
"deprecated": false, "autowired": false, "secret": false, "description": "Sets
the exchange pattern when the consumer creates an exchange." },
- "pollStrategy": { "index": 10, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
- "documentId": { "index": 11, "kind": "parameter", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
- "operation": { "index": 12, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.ca [...]
- "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
- "backoffErrorThreshold": { "index": 14, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
- "backoffIdleThreshold": { "index": 15, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
- "backoffMultiplier": { "index": 16, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
- "delay": { "index": 17, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
- "greedy": { "index": 18, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
- "initialDelay": { "index": 19, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
- "repeatCount": { "index": 20, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
- "runLoggingLevel": { "index": 21, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
- "scheduledExecutorService": { "index": 22, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
- "scheduler": { "index": 23, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
- "schedulerProperties": { "index": 24, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
- "startScheduler": { "index": 25, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
- "timeUnit": { "index": 26, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
- "useFixedDelay": { "index": 27, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." }
+ "maxPendingChanges": { "index": 10, "kind": "parameter", "displayName":
"Max Pending Changes", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 0,
"configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "Maximum number of
realtime document changes [...]
+ "pollStrategy": { "index": 11, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
+ "documentId": { "index": 12, "kind": "parameter", "displayName": "Document
Id", "group": "producer", "label": "producer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.google.firestore.GoogleFirestoreConfiguration",
"configurationField": "configuration", "description": "The document ID to use
for document-specific operations" },
+ "operation": { "index": 13, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "enum", "javaType":
"org.apache.camel.component.google.firestore.GoogleFirestoreOperations",
"enum": [ "setDocument", "getDocumentById", "updateDocument", "deleteDocument",
"queryCollection", "listDocuments", "listCollections", "createDocument" ],
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.ca [...]
+ "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "backoffErrorThreshold": { "index": 15, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
+ "backoffIdleThreshold": { "index": 16, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
+ "backoffMultiplier": { "index": 17, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
+ "delay": { "index": 18, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
+ "greedy": { "index": 19, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
+ "initialDelay": { "index": 20, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
+ "repeatCount": { "index": 21, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
+ "runLoggingLevel": { "index": 22, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
+ "scheduledExecutorService": { "index": 23, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
+ "scheduler": { "index": 24, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
+ "schedulerProperties": { "index": 25, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
+ "startScheduler": { "index": 26, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
+ "timeUnit": { "index": 27, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
+ "useFixedDelay": { "index": 28, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." }
}
}
diff --git
a/components/camel-google/camel-google-firestore/src/main/docs/google-firestore-component.adoc
b/components/camel-google/camel-google-firestore/src/main/docs/google-firestore-component.adoc
index 3fc57d7b5684..62929b4ed958 100644
---
a/components/camel-google/camel-google-firestore/src/main/docs/google-firestore-component.adoc
+++
b/components/camel-google/camel-google-firestore/src/main/docs/google-firestore-component.adoc
@@ -243,6 +243,18 @@ YAML::
----
====
+In real-time mode the document changes reported by the listener are buffered
until the next poll picks them up. That
+buffer is unbounded by default, so a collection changing faster than the route
consumes it makes the buffer grow, and
+it keeps growing while the route is suspended. Set `maxPendingChanges` to
bound it: when the buffer is full the oldest
+buffered change is discarded and a warning is logged, which leaves the route
with the most recent state of the
+collection.
+
+[source,java]
+----
+from("google-firestore://myCollection?realtimeUpdates=true&maxPendingChanges=1000")
+ .to("log:changes");
+----
+
=== Advanced Component Configuration
If you need more control over the `Firestore` client instance configuration,
you can create your own instance and refer to it in your Camel google-firestore
component configuration:
diff --git
a/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConfiguration.java
b/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConfiguration.java
index 0b4fcbb99ab2..655cbacd294b 100644
---
a/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConfiguration.java
+++
b/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConfiguration.java
@@ -62,6 +62,14 @@ public class GoogleFirestoreConfiguration implements
Cloneable, GoogleCommonConf
description = "When true, the consumer will listen for real-time
updates on the collection")
private boolean realtimeUpdates;
+ @UriParam(label = "consumer,advanced", defaultValue = "0",
+ description = "Maximum number of realtime document changes
buffered between two polls. The changes reported by"
+ + " the snapshot listener are buffered until the
next poll picks them up, so a collection"
+ + " changing faster than the route consumes it
makes that buffer grow. When the buffer is full"
+ + " the oldest buffered change is discarded and a
warning is logged. Use 0 for an unbounded"
+ + " buffer. Only used when realtimeUpdates is
enabled.")
+ private int maxPendingChanges;
+
public String getCollectionName() {
return collectionName;
}
@@ -153,6 +161,20 @@ public class GoogleFirestoreConfiguration implements
Cloneable, GoogleCommonConf
this.realtimeUpdates = realtimeUpdates;
}
+ public int getMaxPendingChanges() {
+ return maxPendingChanges;
+ }
+
+ /**
+ * Maximum number of realtime document changes buffered between two polls.
The changes reported by the snapshot
+ * listener are buffered until the next poll picks them up, so a
collection changing faster than the route consumes
+ * it makes that buffer grow. When the buffer is full the oldest buffered
change is discarded and a warning is
+ * logged. Use 0 for an unbounded buffer. Only used when realtimeUpdates
is enabled.
+ */
+ public void setMaxPendingChanges(int maxPendingChanges) {
+ this.maxPendingChanges = maxPendingChanges;
+ }
+
public GoogleFirestoreConfiguration copy() {
try {
return (GoogleFirestoreConfiguration) super.clone();
diff --git
a/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumer.java
b/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumer.java
index d39188edb737..33913bb08edb 100644
---
a/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumer.java
+++
b/components/camel-google/camel-google-firestore/src/main/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumer.java
@@ -16,12 +16,16 @@
*/
package org.apache.camel.component.google.firestore;
+import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
import com.google.cloud.firestore.CollectionReference;
import com.google.cloud.firestore.DocumentChange;
@@ -46,14 +50,19 @@ import org.slf4j.LoggerFactory;
public class GoogleFirestoreConsumer extends ScheduledBatchPollingConsumer {
private static final Logger LOG =
LoggerFactory.getLogger(GoogleFirestoreConsumer.class);
+ private static final long DISCARD_LOG_INTERVAL = 100;
private final GoogleFirestoreEndpoint endpoint;
private ListenerRegistration listenerRegistration;
- private final Queue<Exchange> pendingExchanges = new
ConcurrentLinkedQueue<>();
+ private final BlockingQueue<Exchange> pendingExchanges;
+ private final AtomicLong discardedChanges = new AtomicLong();
public GoogleFirestoreConsumer(GoogleFirestoreEndpoint endpoint, Processor
processor) {
super(endpoint, processor);
this.endpoint = endpoint;
+
+ int max = endpoint.getConfiguration().getMaxPendingChanges();
+ this.pendingExchanges = max > 0 ? new LinkedBlockingQueue<>(max) : new
LinkedBlockingQueue<>();
}
@Override
@@ -72,6 +81,14 @@ public class GoogleFirestoreConsumer extends
ScheduledBatchPollingConsumer {
listenerRegistration = null;
LOG.debug("Realtime listener removed");
}
+
+ List<Exchange> remaining = new ArrayList<>();
+ pendingExchanges.drainTo(remaining);
+ if (!remaining.isEmpty()) {
+ LOG.debug("Releasing {} buffered document changes that were not
polled", remaining.size());
+ remaining.forEach(exchange -> releaseExchange(exchange, false));
+ }
+
super.doStop();
}
@@ -93,7 +110,7 @@ public class GoogleFirestoreConsumer extends
ScheduledBatchPollingConsumer {
for (DocumentChange dc : snapshots.getDocumentChanges()) {
try {
Exchange exchange =
createExchangeFromDocument(dc.getDocument(), dc.getType());
- pendingExchanges.add(exchange);
+ bufferChange(exchange);
} catch (Exception ex) {
LOG.error("Error creating exchange from document
change", ex);
}
@@ -112,17 +129,46 @@ public class GoogleFirestoreConsumer extends
ScheduledBatchPollingConsumer {
}
}
+ /**
+ * The document changes buffered by the realtime listener and not yet
picked up by a poll.
+ */
+ BlockingQueue<Exchange> pendingChanges() {
+ return pendingExchanges;
+ }
+
+ /**
+ * Buffers a document change until the next poll picks it up. The listener
callback runs on a Firestore client
+ * thread, so it must never block waiting for the route to catch up: when
the buffer is bounded and full, the oldest
+ * buffered change is discarded instead, leaving the route with the most
recent state of the collection.
+ */
+ void bufferChange(Exchange exchange) {
+ while (!pendingExchanges.offer(exchange)) {
+ Exchange discarded = pendingExchanges.poll();
+ if (discarded == null) {
+ // the poll drained the buffer in the meantime, so there is
room again
+ continue;
+ }
+
+ releaseExchange(discarded, false);
+ long total = discardedChanges.incrementAndGet();
+ if (total == 1 || total % DISCARD_LOG_INTERVAL == 0) {
+ LOG.warn("The realtime buffer of collection {} is full
(maxPendingChanges={}), discarding the oldest"
+ + " buffered change. {} changes discarded so far.
Raise maxPendingChanges, or make the route"
+ + " consume faster.",
+ endpoint.getConfiguration().getCollectionName(),
+ endpoint.getConfiguration().getMaxPendingChanges(),
total);
+ }
+ }
+ }
+
@Override
protected int poll() throws Exception {
Queue<Exchange> exchanges;
if (endpoint.getConfiguration().isRealtimeUpdates()) {
- // Drain pending exchanges from realtime listener (lock-free)
+ // Drain pending exchanges from realtime listener
exchanges = new LinkedList<>();
- Exchange e;
- while ((e = pendingExchanges.poll()) != null) {
- exchanges.add(e);
- }
+ pendingExchanges.drainTo(exchanges);
} else {
// Poll the collection
exchanges = pollCollection();
@@ -189,6 +235,12 @@ public class GoogleFirestoreConsumer extends
ScheduledBatchPollingConsumer {
getAsyncProcessor().process(exchange, EmptyAsyncCallback.get());
}
+ // the batch is interrupted when the consumer is stopping, so release
what is left over
+ Exchange remaining;
+ while ((remaining = (Exchange) exchanges.poll()) != null) {
+ releaseExchange(remaining, false);
+ }
+
return total;
}
diff --git
a/components/camel-google/camel-google-firestore/src/test/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumerBufferTest.java
b/components/camel-google/camel-google-firestore/src/test/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumerBufferTest.java
new file mode 100644
index 000000000000..6c3c25677f1b
--- /dev/null
+++
b/components/camel-google/camel-google-firestore/src/test/java/org/apache/camel/component/google/firestore/GoogleFirestoreConsumerBufferTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.component.google.firestore;
+
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Verifies how the realtime listener buffers the document changes it reports.
Uses direct object construction to avoid
+ * starting the endpoint, which requires Google Cloud credentials.
+ */
+class GoogleFirestoreConsumerBufferTest {
+
+ private DefaultCamelContext context;
+
+ @AfterEach
+ void tearDown() {
+ if (context != null) {
+ context.stop();
+ }
+ }
+
+ private GoogleFirestoreConsumer consumer(int maxPendingChanges) {
+ context = new DefaultCamelContext();
+
+ GoogleFirestoreConfiguration configuration = new
GoogleFirestoreConfiguration();
+ configuration.setCollectionName("users");
+ configuration.setRealtimeUpdates(true);
+ configuration.setMaxPendingChanges(maxPendingChanges);
+
+ GoogleFirestoreComponent component = new
GoogleFirestoreComponent(context);
+ GoogleFirestoreEndpoint endpoint = new
GoogleFirestoreEndpoint("google-firestore:users", component, configuration);
+
+ return new GoogleFirestoreConsumer(endpoint, exchange -> {
+ });
+ }
+
+ private Exchange change(GoogleFirestoreConsumer consumer, String
documentId) {
+ Exchange exchange = new DefaultExchange(context);
+
exchange.getIn().setHeader(GoogleFirestoreConstants.RESPONSE_DOCUMENT_ID,
documentId);
+ consumer.bufferChange(exchange);
+ return exchange;
+ }
+
+ private List<String> bufferedDocumentIds(GoogleFirestoreConsumer consumer)
{
+ return consumer.pendingChanges().stream()
+ .map(exchange ->
exchange.getIn().getHeader(GoogleFirestoreConstants.RESPONSE_DOCUMENT_ID,
String.class))
+ .toList();
+ }
+
+ @Test
+ void theBufferIsUnboundedByDefault() {
+ GoogleFirestoreConsumer consumer = consumer(0);
+
+ for (int i = 0; i < 500; i++) {
+ change(consumer, "doc-" + i);
+ }
+
+ assertThat(consumer.pendingChanges()).hasSize(500);
+ }
+
+ @Test
+ void theOldestChangeIsDiscardedWhenTheBufferIsFull() {
+ GoogleFirestoreConsumer consumer = consumer(3);
+
+ change(consumer, "doc-1");
+ change(consumer, "doc-2");
+ change(consumer, "doc-3");
+ change(consumer, "doc-4");
+ change(consumer, "doc-5");
+
+ // the route is left with the most recent state of the collection
+ assertThat(bufferedDocumentIds(consumer)).containsExactly("doc-3",
"doc-4", "doc-5");
+ }
+
+ @Test
+ void aBufferOfOneKeepsOnlyTheLastChange() {
+ GoogleFirestoreConsumer consumer = consumer(1);
+
+ change(consumer, "doc-1");
+ change(consumer, "doc-2");
+
+ assertThat(bufferedDocumentIds(consumer)).containsExactly("doc-2");
+ }
+}
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleFirestoreComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleFirestoreComponentBuilderFactory.java
index f0e4a65ddab8..375d966f8f69 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleFirestoreComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GoogleFirestoreComponentBuilderFactory.java
@@ -178,6 +178,27 @@ public interface GoogleFirestoreComponentBuilderFactory {
return this;
}
+ /**
+ * Maximum number of realtime document changes buffered between two
+ * polls. The changes reported by the snapshot listener are buffered
+ * until the next poll picks them up, so a collection changing faster
+ * than the route consumes it makes that buffer grow. When the buffer
is
+ * full the oldest buffered change is discarded and a warning is
logged.
+ * Use 0 for an unbounded buffer. Only used when realtimeUpdates is
+ * enabled.
+ *
+ * The option is a: <code>int</code> type.
+ *
+ * Group: consumer (advanced)
+ *
+ * @param maxPendingChanges the value to set
+ * @return the dsl builder
+ */
+ default GoogleFirestoreComponentBuilder maxPendingChanges(int
maxPendingChanges) {
+ doSetProperty("maxPendingChanges", maxPendingChanges);
+ return this;
+ }
+
/**
* The document ID to use for document-specific operations.
*
@@ -321,6 +342,7 @@ public interface GoogleFirestoreComponentBuilderFactory {
case "serviceAccountKey":
getOrCreateConfiguration((GoogleFirestoreComponent)
component).setServiceAccountKey((java.lang.String) value); return true;
case "bridgeErrorHandler": ((GoogleFirestoreComponent)
component).setBridgeErrorHandler((boolean) value); return true;
case "realtimeUpdates":
getOrCreateConfiguration((GoogleFirestoreComponent)
component).setRealtimeUpdates((boolean) value); return true;
+ case "maxPendingChanges":
getOrCreateConfiguration((GoogleFirestoreComponent)
component).setMaxPendingChanges((int) value); return true;
case "documentId":
getOrCreateConfiguration((GoogleFirestoreComponent)
component).setDocumentId((java.lang.String) value); return true;
case "lazyStartProducer": ((GoogleFirestoreComponent)
component).setLazyStartProducer((boolean) value); return true;
case "operation":
getOrCreateConfiguration((GoogleFirestoreComponent)
component).setOperation((org.apache.camel.component.google.firestore.GoogleFirestoreOperations)
value); return true;
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleFirestoreEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleFirestoreEndpointBuilderFactory.java
index 72e3b7a18e6b..a77763ded14e 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleFirestoreEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleFirestoreEndpointBuilderFactory.java
@@ -769,6 +769,48 @@ public interface GoogleFirestoreEndpointBuilderFactory {
doSetProperty("exchangePattern", exchangePattern);
return this;
}
+ /**
+ * Maximum number of realtime document changes buffered between two
+ * polls. The changes reported by the snapshot listener are buffered
+ * until the next poll picks them up, so a collection changing faster
+ * than the route consumes it makes that buffer grow. When the buffer
is
+ * full the oldest buffered change is discarded and a warning is
logged.
+ * Use 0 for an unbounded buffer. Only used when realtimeUpdates is
+ * enabled.
+ *
+ * The option is a: <code>int</code> type.
+ *
+ * Default: 0
+ * Group: consumer (advanced)
+ *
+ * @param maxPendingChanges the value to set
+ * @return the dsl builder
+ */
+ default AdvancedGoogleFirestoreEndpointConsumerBuilder
maxPendingChanges(int maxPendingChanges) {
+ doSetProperty("maxPendingChanges", maxPendingChanges);
+ return this;
+ }
+ /**
+ * Maximum number of realtime document changes buffered between two
+ * polls. The changes reported by the snapshot listener are buffered
+ * until the next poll picks them up, so a collection changing faster
+ * than the route consumes it makes that buffer grow. When the buffer
is
+ * full the oldest buffered change is discarded and a warning is
logged.
+ * Use 0 for an unbounded buffer. Only used when realtimeUpdates is
+ * enabled.
+ *
+ * The option will be converted to a <code>int</code> type.
+ *
+ * Default: 0
+ * Group: consumer (advanced)
+ *
+ * @param maxPendingChanges the value to set
+ * @return the dsl builder
+ */
+ default AdvancedGoogleFirestoreEndpointConsumerBuilder
maxPendingChanges(String maxPendingChanges) {
+ doSetProperty("maxPendingChanges", maxPendingChanges);
+ return this;
+ }
/**
* A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing
* you to provide your custom implementation to control error handling