Conversation monitors now allow **10,000,000 calls per UTC month** and
**500,000 calls per UTC day**, per account. Allowances count attempted
provider requests, including preview calls, and no longer depend on
estimated token lengths. Pending evaluations retain their quota holds
when new messages arrive and resume after the applicable reset without
retrying ahead of a provider cooldown.
## What changed
- Enforce both call limits using persisted daily usage under the account
lock, so concurrent workers cannot exceed the remaining allowance. Each
attempted provider batch consumes one call, even when it evaluates
multiple monitors or returns a provider error.
- Remove the daily token reservation and reconciliation, which mixed
JSON request bytes with provider input tokens. Keep request-size limits
and provider token/cost telemetry.
- Preserve daily and monthly quota holds across new conversation input.
Spread retries over up to four hours after the later of the quota reset
and the longest provider cooldown recorded across failed batches.
- Report when the current monthly allowance was reached, ignoring
timestamps from the previous 100,000-call allowance.
- Document the RubyLLM bundle-audit exceptions for the pinned Ruby 3.4.4
runtime, with reassessment required when the runtime or supported
dependency versions change.
## Quota logging
When a committed call reaches the daily or monthly account cap, emit one
structured `conversation_monitor_limit_reached` log event for that
period. It includes `account_id`, `period` (`daily` or `monthly`),
`used`, `limit`, and the UTC reset timestamp `resets_at`. Rolled-back
calls and subsequent blocked retries do not emit events. Reaching both
caps in the same call emits one event for each period.
The event uses the existing Rails log forwarding path. In New Relic,
group events by account and period with:
```sql
FROM Log
WITH aparse(message, '%"account_id":*,%') AS account_id,
aparse(message, '%"period":"*"%') AS period
SELECT count(*)
WHERE message LIKE '%conversation_monitor_limit_reached%'
FACET account_id, period
SINCE 7 days ago
LIMIT MAX
```
## Closes
Fixes https://linear.app/chatwoot/issue/INF-117
## How to reproduce
1. Exhaust an account's daily allowance, then receive additional
conversation messages before the next UTC midnight. Previously, each
message could pull the held work into an early retry and accumulate
another job at the reset. The work now retains its saved retry time
while recording the new input.
2. Have an earlier provider batch return a long `Retry-After`, then
exhaust the daily or monthly allowance before the next batch. The saved
retry now honors both the allowance reset and the longer provider
cooldown before adding jitter.
## Rollout
Existing quota holds retain their saved retry times; the increased
allowances apply when work next reserves a call. Already-scheduled jobs
from before deployment will still run once.
---------
Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
352 lines
14 KiB
Plaintext
352 lines
14 KiB
Plaintext
# Learn about the various environment variables at
|
|
# https://www.chatwoot.com/docs/self-hosted/configuration/environment-variables/#rails-production-variables
|
|
|
|
# Used to verify the integrity of signed cookies. so ensure a secure value is set
|
|
# SECRET_KEY_BASE should be alphanumeric. Avoid special characters or symbols.
|
|
# Use `rake secret` to generate this variable
|
|
SECRET_KEY_BASE=replace_with_lengthy_secure_hex
|
|
|
|
# Active Record Encryption keys (required for MFA/2FA functionality)
|
|
# Generate these keys by running: rails db:encryption:init
|
|
# IMPORTANT: Use different keys for each environment (development, staging, production)
|
|
# ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=
|
|
# ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
|
|
# ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=
|
|
|
|
# Replace with the URL you are planning to use for your app
|
|
FRONTEND_URL=http://0.0.0.0:3000
|
|
|
|
# Enterprise conversation monitors (enable the conversation_monitors account feature separately)
|
|
# Set CAPTAIN_OPENROUTER_API_KEY and optional CAPTAIN_OPENROUTER_DECISION_MODEL_ENDPOINT
|
|
# in Super Admin -> Settings -> Captain (shared installation settings). The endpoint is the API base URL.
|
|
# CONVERSATION_MONITORS_MODEL=typesafe/jev-1.13
|
|
# CONVERSATION_MONITORS_LIMIT=20
|
|
# Allowlisted contact/conversation custom attribute keys to send as customer context
|
|
# CONVERSATION_MONITORS_ATTRIBUTES=deployment_type
|
|
# Each account can make 500,000 monitor calls per UTC day and 10,000,000 per UTC month.
|
|
# To use a dedicated URL for help center pages
|
|
# HELPCENTER_URL=http://0.0.0.0:3000
|
|
|
|
# If the variable is set, all non-authenticated pages would fallback to the default locale.
|
|
# Whenever a new account is created, the default language will be DEFAULT_LOCALE instead of en
|
|
# DEFAULT_LOCALE=en
|
|
|
|
# If you plan to use CDN for your assets, set Asset CDN Host
|
|
ASSET_CDN_HOST=
|
|
|
|
# Force all access to the app over SSL, default is set to false
|
|
FORCE_SSL=false
|
|
|
|
# This lets you control new sign ups on your chatwoot installation
|
|
# true : default option, allows sign ups
|
|
# false : disables all the end points related to sign ups
|
|
# api_only: disables the UI for signup, but you can create sign ups via the account apis
|
|
ENABLE_ACCOUNT_SIGNUP=false
|
|
|
|
# Redis config
|
|
# specify the configs via single URL or individual variables
|
|
# ref: https://www.iana.org/assignments/uri-schemes/prov/redis
|
|
# You can also use the following format for the URL: redis://:password@host:port/db_number
|
|
REDIS_URL=redis://redis:6379
|
|
# If you are using docker-compose, set this variable's value to be any string,
|
|
# which will be the password for the redis service running inside the docker-compose
|
|
# to make it secure
|
|
REDIS_PASSWORD=
|
|
# Redis Sentinel can be used by passing list of sentinel host and ports e,g. sentinel_host1:port1,sentinel_host2:port2
|
|
REDIS_SENTINELS=
|
|
# Redis sentinel master name is required when using sentinel, default value is "mymaster".
|
|
# You can find list of master using "SENTINEL masters" command
|
|
REDIS_SENTINEL_MASTER_NAME=
|
|
|
|
# By default Chatwoot will pass REDIS_PASSWORD as the password value for sentinels
|
|
# Use the following environment variable to customize passwords for sentinels.
|
|
# Use empty string if sentinels are configured with out passwords
|
|
# REDIS_SENTINEL_PASSWORD=
|
|
|
|
# Redis premium breakage in heroku fix
|
|
# enable the following configuration
|
|
# ref: https://github.com/chatwoot/chatwoot/issues/2420
|
|
# REDIS_OPENSSL_VERIFY_MODE=none
|
|
|
|
# OpenSearch / Elasticsearch-compatible search config
|
|
# Set OPENSEARCH_URL to enable advanced search. Elastic Cloud API keys can be configured with either key name below.
|
|
# API key values must be provided without the ApiKey authorization scheme prefix.
|
|
# OPENSEARCH_URL=
|
|
# OPENSEARCH_API_KEY=
|
|
# ELASTICSEARCH_API_KEY=
|
|
# OPENSEARCH_AWS_ACCESS_KEY_ID=
|
|
# OPENSEARCH_AWS_SECRET_ACCESS_KEY=
|
|
# OPENSEARCH_AWS_REGION=us-east-1
|
|
|
|
# Postgres Database config variables
|
|
# You can leave POSTGRES_DATABASE blank. The default name of
|
|
# the database in the production environment is chatwoot_production
|
|
# POSTGRES_DATABASE=
|
|
POSTGRES_HOST=postgres
|
|
POSTGRES_USERNAME=postgres
|
|
POSTGRES_PASSWORD=
|
|
RAILS_ENV=development
|
|
# Changes the Postgres query timeout limit. The default is 14 seconds. Modify only when required.
|
|
# POSTGRES_STATEMENT_TIMEOUT=14s
|
|
RAILS_MAX_THREADS=5
|
|
# Number of Puma worker processes (clustered mode). Defaults to 0 (single
|
|
# process) when unset. On a multi-core production server, set this to run Puma
|
|
# in clustered mode so CPU-bound requests don't serialize behind Ruby's GVL.
|
|
# A common starting point is the number of available CPU cores; total
|
|
# concurrency is roughly WEB_CONCURRENCY * RAILS_MAX_THREADS, so size it
|
|
# against available RAM. See config/puma.rb.
|
|
# WEB_CONCURRENCY=2
|
|
|
|
# The email from which all outgoing emails are sent
|
|
# could user either `email@yourdomain.com` or `BrandName <email@yourdomain.com>`
|
|
MAILER_SENDER_EMAIL=Chatwoot <accounts@chatwoot.com>
|
|
|
|
#SMTP domain key is set up for HELO checking
|
|
SMTP_DOMAIN=chatwoot.com
|
|
# Set the value to "mailhog" if using docker-compose for development environments,
|
|
# Set the value as "localhost" or your SMTP address in other environments
|
|
# If SMTP_ADDRESS is empty, Chatwoot would try to use sendmail(postfix)
|
|
SMTP_ADDRESS=
|
|
SMTP_PORT=1025
|
|
SMTP_USERNAME=
|
|
SMTP_PASSWORD=
|
|
# plain,login,cram_md5
|
|
SMTP_AUTHENTICATION=
|
|
SMTP_ENABLE_STARTTLS_AUTO=true
|
|
# Can be: 'none', 'peer', 'client_once', 'fail_if_no_peer_cert', see http://api.rubyonrails.org/classes/ActionMailer/Base.html
|
|
SMTP_OPENSSL_VERIFY_MODE=peer
|
|
# Comment out the following environment variables if required by your SMTP server
|
|
# SMTP_TLS=
|
|
# SMTP_SSL=
|
|
# SMTP_OPEN_TIMEOUT
|
|
# SMTP_READ_TIMEOUT
|
|
|
|
# Mail Incoming
|
|
# This is the domain set for the reply emails when conversation continuity is enabled
|
|
MAILER_INBOUND_EMAIL_DOMAIN=
|
|
# Maximum time in seconds to process a single IMAP email
|
|
# EMAIL_PROCESSING_TIMEOUT_SECONDS=60
|
|
# Set this to the appropriate ingress channel with regards to incoming emails
|
|
# Possible values are :
|
|
# relay for Exim, Postfix, Qmail
|
|
# mailgun for Mailgun
|
|
# mandrill for Mandrill
|
|
# postmark for Postmark
|
|
# sendgrid for Sendgrid
|
|
# ses for Amazon SES
|
|
RAILS_INBOUND_EMAIL_SERVICE=
|
|
# Use one of the following based on the email ingress service
|
|
# Ref: https://edgeguides.rubyonrails.org/action_mailbox_basics.html
|
|
# Set this to a password of your choice and use it in the Inbound webhook
|
|
RAILS_INBOUND_EMAIL_PASSWORD=
|
|
|
|
MAILGUN_INGRESS_SIGNING_KEY=
|
|
MANDRILL_INGRESS_API_KEY=
|
|
|
|
# SNS topic ARN for ActionMailbox (format: arn:aws:sns:region:account-id:topic-name)
|
|
# Configure only if the rails_inbound_email_service = ses
|
|
ACTION_MAILBOX_SES_SNS_TOPIC=
|
|
|
|
# Creating Your Inbound Webhook Instructions for Postmark and Sendgrid:
|
|
# Inbound webhook URL format:
|
|
# https://actionmailbox:[YOUR_RAILS_INBOUND_EMAIL_PASSWORD]@[YOUR_CHATWOOT_DOMAIN.COM]/rails/action_mailbox/[RAILS_INBOUND_EMAIL_SERVICE]/inbound_emails
|
|
# Note: Replace the values inside the brackets; do not include the brackets themselves.
|
|
# Example: https://actionmailbox:mYRandomPassword3@chatwoot.example.com/rails/action_mailbox/postmark/inbound_emails
|
|
# For Postmark
|
|
# Ensure the 'Include raw email content in JSON payload' checkbox is selected in the inbound webhook section.
|
|
|
|
# Storage
|
|
ACTIVE_STORAGE_SERVICE=local
|
|
|
|
# Restrict libvips to its trusted, well-tested image loaders when Active Storage
|
|
# generates variants. Hardens image processing against untrusted uploads.
|
|
# Requires libvips >= 8.13 (ignored on older versions).
|
|
VIPS_BLOCK_UNTRUSTED=1
|
|
|
|
# Amazon S3
|
|
# documentation: https://www.chatwoot.com/docs/configuring-s3-bucket-as-cloud-storage
|
|
S3_BUCKET_NAME=
|
|
AWS_ACCESS_KEY_ID=
|
|
AWS_SECRET_ACCESS_KEY=
|
|
AWS_REGION=
|
|
|
|
# Log settings
|
|
# Disable if you want to write logs to a file
|
|
RAILS_LOG_TO_STDOUT=true
|
|
LOG_LEVEL=info
|
|
LOG_SIZE=500
|
|
# Configure this environment variable if you want to use lograge instead of rails logger
|
|
#LOGRAGE_ENABLED=true
|
|
|
|
### This environment variables are only required if you are setting up social media channels
|
|
|
|
# Facebook
|
|
# documentation: https://www.chatwoot.com/docs/facebook-setup
|
|
# Connected Facebook pages are subscribed by Chatwoot to Messenger webhook
|
|
# fields, including postbacks used by Get Started and button flows.
|
|
FB_VERIFY_TOKEN=
|
|
FB_APP_SECRET=
|
|
FB_APP_ID=
|
|
|
|
# https://developers.facebook.com/docs/messenger-platform/instagram/get-started#app-dashboard
|
|
IG_VERIFY_TOKEN=
|
|
|
|
# Twitter
|
|
# documentation: https://www.chatwoot.com/docs/twitter-app-setup
|
|
TWITTER_APP_ID=
|
|
TWITTER_CONSUMER_KEY=
|
|
TWITTER_CONSUMER_SECRET=
|
|
TWITTER_ENVIRONMENT=
|
|
|
|
#slack integration
|
|
SLACK_CLIENT_ID=
|
|
SLACK_CLIENT_SECRET=
|
|
SLACK_SIGNING_SECRET=
|
|
|
|
# Google OAuth
|
|
GOOGLE_OAUTH_CLIENT_ID=
|
|
GOOGLE_OAUTH_CLIENT_SECRET=
|
|
GOOGLE_OAUTH_CALLBACK_URL=
|
|
|
|
### Change this env variable only if you are using a custom build mobile app
|
|
## Mobile app env variables
|
|
IOS_APP_ID=L7YLMN4634.com.chatwoot.app
|
|
ANDROID_BUNDLE_ID=com.chatwoot.app
|
|
|
|
# https://developers.google.com/android/guides/client-auth (use keytool to print the fingerprint in the first section)
|
|
ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:D4:5D:D4:53:F8:3B:FB:D3:C6:28:64:1D:AA:08:1E:D8
|
|
|
|
### Smart App Banner
|
|
# https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html
|
|
# You can find your app-id in https://itunesconnect.apple.com
|
|
#IOS_APP_IDENTIFIER=1495796682
|
|
|
|
## Push Notification
|
|
## generate a new key value here : https://d3v.one/vapid-key-generator/
|
|
# VAPID_PUBLIC_KEY=
|
|
# VAPID_PRIVATE_KEY=
|
|
#
|
|
# for mobile apps
|
|
# FCM_SERVER_KEY=
|
|
|
|
### APM and Error Monitoring configurations
|
|
## Elastic APM
|
|
## https://www.elastic.co/guide/en/apm/agent/ruby/current/getting-started-rails.html
|
|
# ELASTIC_APM_SERVER_URL=
|
|
# ELASTIC_APM_SECRET_TOKEN=
|
|
|
|
## Sentry
|
|
# SENTRY_DSN=
|
|
|
|
|
|
## Scout
|
|
## https://scoutapm.com/docs/ruby/configuration
|
|
# SCOUT_KEY=YOURKEY
|
|
# SCOUT_NAME=YOURAPPNAME (Production)
|
|
# SCOUT_MONITOR=true
|
|
|
|
## NewRelic
|
|
# https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/
|
|
# NEW_RELIC_LICENSE_KEY=
|
|
# Set this to true to allow newrelic apm to send logs.
|
|
# This is turned off by default.
|
|
# NEW_RELIC_APPLICATION_LOGGING_ENABLED=
|
|
|
|
## Datadog
|
|
## https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#environment-variables
|
|
# DD_TRACE_AGENT_URL=
|
|
|
|
|
|
# MaxMindDB API key to download GeoLite2 City database
|
|
# IP_LOOKUP_API_KEY=
|
|
|
|
## Rack Attack configuration
|
|
## To prevent and throttle abusive requests
|
|
# ENABLE_RACK_ATTACK=true
|
|
# RACK_ATTACK_LIMIT=300
|
|
## Parent switch for all widget throttles; per-endpoint switches below only apply when this is on
|
|
# ENABLE_RACK_ATTACK_WIDGET_API=true
|
|
## Widget conversation creates, per minute, keyed on (IP, website_token)
|
|
# ENABLE_RACK_ATTACK_WIDGET_CONVERSATIONS=true
|
|
# RATE_LIMIT_WIDGET_CONVERSATIONS=30
|
|
## Widget message creates, per minute, keyed on (IP, website_token)
|
|
# ENABLE_RACK_ATTACK_WIDGET_MESSAGES=true
|
|
# RATE_LIMIT_WIDGET_MESSAGES=60
|
|
## Widget contact updates, per hour, per IP
|
|
# ENABLE_RACK_ATTACK_WIDGET_CONTACTS=true
|
|
# RATE_LIMIT_WIDGET_CONTACTS=60
|
|
## Widget page loads (new session), per hour, per IP
|
|
# ENABLE_RACK_ATTACK_WIDGET_LOAD=true
|
|
# RATE_LIMIT_WIDGET_LOAD=200
|
|
## Widget transcript requests, per hour, per IP
|
|
# ENABLE_RACK_ATTACK_WIDGET_TRANSCRIPT=true
|
|
# RATE_LIMIT_WIDGET_TRANSCRIPT=5
|
|
# Comma-separated list of trusted IPs that bypass Rack Attack throttling rules
|
|
# RACK_ATTACK_ALLOWED_IPS=127.0.0.1,::1,192.168.0.10
|
|
|
|
## SafeFetch private network access
|
|
## Keep disabled by default. Self-hosted installations can enable this to allow SafeFetch requests to private network URLs.
|
|
# SAFE_FETCH_ALLOW_PRIVATE_NETWORK=false
|
|
|
|
## Running chatwoot as an API only server
|
|
## setting this value to true will disable the frontend dashboard endpoints
|
|
# CW_API_ONLY_SERVER=false
|
|
|
|
## Development Only Config
|
|
# if you want to use letter_opener for local emails
|
|
# LETTER_OPENER=true
|
|
# meant to be used in github codespaces
|
|
# WEBPACKER_DEV_SERVER_PUBLIC=
|
|
|
|
# If you want to use official mobile app,
|
|
# the notifications would be relayed via a Chatwoot server
|
|
ENABLE_PUSH_RELAY_SERVER=true
|
|
|
|
# Stripe API key
|
|
STRIPE_SECRET_KEY=
|
|
STRIPE_WEBHOOK_SECRET=
|
|
|
|
# Set to true if you want to upload files to cloud storage using the signed url
|
|
# Make sure to follow https://edgeguides.rubyonrails.org/active_storage_overview.html#cross-origin-resource-sharing-cors-configuration on the cloud storage after setting this to true.
|
|
DIRECT_UPLOADS_ENABLED=
|
|
|
|
#MS OAUTH creds
|
|
AZURE_APP_ID=
|
|
AZURE_APP_SECRET=
|
|
|
|
## Advanced configurations
|
|
## Change these values to fine tune performance
|
|
# control the concurrency setting of sidekiq
|
|
# SIDEKIQ_CONCURRENCY=10
|
|
# Enable verbose logging each time a job is dequeued in Sidekiq
|
|
# ENABLE_SIDEKIQ_DEQUEUE_LOGGER=false
|
|
|
|
# Sidekiq health check server (defaults to 0.0.0.0:7433).
|
|
# Uncomment SIDEKIQ_ALIVE_HOST to restrict the health check to localhost.
|
|
# SIDEKIQ_ALIVE_HOST=127.0.0.1
|
|
# SIDEKIQ_ALIVE_PORT=7433
|
|
|
|
# AI powered features (Captain)
|
|
# The OpenAI API key and endpoint for Captain are not configured via .env.
|
|
# Set them at Super Admin > App Configs > Captain (CAPTAIN_OPEN_AI_API_KEY, CAPTAIN_OPEN_AI_ENDPOINT).
|
|
|
|
# Housekeeping/Performance related configurations
|
|
# Set to true if you want to remove stale contact inboxes
|
|
# contact_inboxes with no conversation older than 90 days will be removed
|
|
# REMOVE_STALE_CONTACT_INBOX_JOB_STATUS=false
|
|
|
|
# REDIS_ALFRED_SIZE=10
|
|
# REDIS_VELMA_SIZE=10
|
|
|
|
# Publish Sidekiq queue metrics to AWS CloudWatch for autoscaling. Off by default.
|
|
# By default uses the instance role, which must allow cloudwatch:PutMetricData.
|
|
# ENABLE_SIDEKIQ_CLOUDWATCH=true
|
|
# SIDEKIQ_CLOUDWATCH_NAMESPACE=Chatwoot/Sidekiq
|
|
# Publish interval in seconds (default 60; values below 60 work but bill as high-resolution CloudWatch metrics)
|
|
# SIDEKIQ_CLOUDWATCH_INTERVAL=60
|
|
# Optional: dedicated credentials for CloudWatch only, separate from the S3 (storage) keys.
|
|
# Set these to override the instance role when a role is not available.
|
|
# SIDEKIQ_CLOUDWATCH_AWS_ACCESS_KEY_ID=
|
|
# SIDEKIQ_CLOUDWATCH_AWS_SECRET_ACCESS_KEY=
|
|
# SIDEKIQ_CLOUDWATCH_AWS_REGION=us-east-1
|