# Pull Request Template ## Description Large emails (2MB+ with multiple attachments) were causing IMAP email processing jobs to timeout silently, blocking all subsequent emails from being processed. This created an infinite loop where: - Problematic emails were repeatedly fetched but never successfully processed - Other emails in the queue were never processed as we iterated sequentially - silent failures ### Solution Enhanced the FetchImapEmailsJob with individual email processing isolation: ### Key Changes 1. Individual Email Processing: Changed from map to each for better memory efficiency 2. Timeout Protection: Added configurable timeout per email (default: 60 seconds) 3. Failure Tracking: Track failed emails with 6-hour expiry for retry opportunities 4. Skip Logic: Skip emails that have failed 3+ times to prevent infinite loops 5. Error Isolation: Each email is processed in its own error boundary ### Configuration - Timeout: Configurable via EMAIL_PROCESSING_TIMEOUT_SECONDS using GlobalConfigService - Default: 60 seconds per email - Failure Limit: 3 attempts before skipping - Retry Window: 6 hours so that emails get 8 more chances in the 2 day window ### Benefits - Prevents queue blocking: One problematic email cannot stop others - Maintains email order: Older emails (customers waiting longer) processed first - Automatic recovery: Failed emails get retry opportunities - Better monitoring: Clear logging when emails timeout or are skipped - Configurable: Deployments can adjust the timeout based on their needs This fix ensures email processing reliability while maintaining existing functionality. ## Type of change Please delete options that are not relevant. - [x] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules
282 lines
10 KiB
Bash
282 lines
10 KiB
Bash
# 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
|
|
# 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
|
|
|
|
# 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
|
|
|
|
# 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
|
|
|
|
# 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
|
|
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=
|
|
|
|
# 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
|
|
# ENABLE_RACK_ATTACK_WIDGET_API=true
|
|
# 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
|
|
|
|
## 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
|
|
|
|
|
|
# AI powered features
|
|
## OpenAI key
|
|
# OPENAI_API_KEY=
|
|
|
|
# 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
|