Skip to main content

๐Ÿงน Cleanup Domains

๐Ÿ“– Overviewโ€‹

The Cleanup Domains job removes orphaned and inactive Lightning Domains that fail SSL validation or remain non-active for extended periods. It runs every 6 hours, identifies domains created 7+ days ago with non-active status or SSL issues, verifies current Cloudflare status, and deletes domains that remain inactive for 14+ days. This ensures database hygiene and prevents accumulation of failed domain provisioning attempts.

Complete Flow:

  1. Cron Initialization: queue-manager/crons/domains/cleanup.js
  2. Service Processing: queue-manager/services/domains/cleanup.js
  3. Queue Definition: queue-manager/queues/domains/cleanup.js

Execution Pattern: Scheduled (every 6 hours)

Queue Name: domains_cleanup

Environment Flag: QM_DOMAINS_CLEANUP=true (in index.js)

๐Ÿ”„ Complete Processing Flowโ€‹

sequenceDiagram
participant CRON as Cron Schedule<br/>(every 6 hours)
participant SERVICE as Cleanup Service
participant LD_DB as Lightning<br/>Domains DB
participant QUEUE as Bull Queue
participant PROCESSOR as Job Processor
participant CF_API as Cloudflare API
participant FUNNEL_DB as Funnels DB

CRON->>SERVICE: cleanup()
SERVICE->>SERVICE: Calculate 7 days ago:<br/>nDaysAgo = now - 7 days

SERVICE->>LD_DB: Find inactive domains:<br/>- (status โ‰  'active' OR ssl.status โ‰  'active')<br/>- created_at < 7 days ago
LD_DB-->>SERVICE: Inactive/problematic domains

alt Domains found
loop Each domain
SERVICE->>QUEUE: Add job: {domain}
end

loop Each queued domain
QUEUE->>PROCESSOR: Process cleanup

alt Missing cf_id
PROCESSOR->>PROCESSOR: Log error, skip
end

PROCESSOR->>CF_API: GET /custom_hostnames/{cf_id}
CF_API-->>PROCESSOR: Domain details OR 404

alt Domain not found in Cloudflare
PROCESSOR->>LD_DB: deleteOne: Remove orphaned record
PROCESSOR->>FUNNEL_DB: reviewAndSetStatusForDomain
PROCESSOR-->>QUEUE: done()
else Domain found but status changed
alt Status or SSL status changed
PROCESSOR->>LD_DB: updateOne: Sync from Cloudflare

alt New status not active
PROCESSOR->>FUNNEL_DB: reviewAndSetStatusForDomain
end
end
else Domain still inactive
alt Created > 14 days ago
PROCESSOR->>CF_API: DELETE /custom_hostnames/{cf_id}
CF_API-->>PROCESSOR: Deletion success
PROCESSOR->>LD_DB: deleteOne: Remove from database
PROCESSOR->>FUNNEL_DB: reviewAndSetStatusForDomain
else Created 7-14 days ago
PROCESSOR->>PROCESSOR: Skip (placeholder for notification)
end
end

PROCESSOR-->>QUEUE: done()
end
end

๐Ÿ“ Source Filesโ€‹

1. Cron Initializationโ€‹

File: queue-manager/crons/domains/cleanup.js

Purpose: Schedule domain cleanup every 6 hours

Cron Pattern: 0 */6 * * * (every 6 hours at minute 0)

Initialization:

const cleanup = require('../../services/domains/cleanup');
const cron = require('node-cron');
const logger = require('../../utilities/logger');

let inProgress = false;
exports.start = async () => {
try {
cron.schedule('0 */6 * * *', async () => {
if (!inProgress) {
inProgress = true;
await cleanup();
inProgress = false;
}
});
} catch (err) {
logger.error({ initiator: 'QM/domains/cleanup', error: err });
}
};

In-Progress Lock: Prevents overlapping executions.

Why Every 6 Hours?

  • Balances cleanup frequency with API usage
  • 7-14 day grace period means hourly checks unnecessary
  • Reduces Cloudflare API load

2. Service Processing (THE INACTIVE DOMAIN DETECTION)โ€‹

File: queue-manager/services/domains/cleanup.js

Purpose: Find domains with inactive status or SSL issues created 7+ days ago

Key Functions:

  • Calculate 7-day lookback window
  • Query domains with non-active status or SSL issues
  • Queue all matching domains for processing

Main Processing Function:

const { default: axios } = require('axios');
const Queue = require('../../queues/domains/cleanup');
const LightningDomain = require('../../models/lightning-domain');
const logger = require('../../utilities/logger');

module.exports = async () => {
try {
const nDaysAgo = new Date();
//setting to 7 days ago
nDaysAgo.setDate(nDaysAgo.getDate() - 7);

// Handle the promise returned by LightningDomain.find
await LightningDomain.find({
$or: [
{ status: { $ne: 'active' } }, // Domain not active
{ 'ssl.status': { $ne: 'active' } }, // SSL not active
],
created_at: { $lt: nDaysAgo }, // Created over 7 days ago
})
.then(async domains => {
// If domains are found, proceed with the queue
if (domains.length) {
const queue = await Queue.start();
for (const domain of domains) {
queue.add(
{ domain },
{
attempts: 3,
},
);
}
}

logger.log({
initiator: 'QM/domains/cleanup',
message: 'Domain Cleanup service processed.',
});
})
.catch(err => {
// Log the error if the database query failed
logger.error({
initiator: 'QM/domains/cleanup',
message: 'Error fetching domains for cleanup',
error: err,
});
});
} catch (err) {
logger.error({ initiator: 'QM/domains/cleanup', error: err });
}
};

3. Queue Processor (THE MULTI-STAGE CLEANUP LOGIC)โ€‹

File: queue-manager/queues/domains/cleanup.js

Purpose: Verify Cloudflare status, sync changes, delete old inactive domains

Key Functions:

  • Fetch current Cloudflare domain status
  • Handle orphaned domains (not found in Cloudflare)
  • Sync status changes from Cloudflare
  • Delete domains inactive for 14+ days
  • Update funnel status for affected domains

Main Processor:

const QueueWrapper = require('../../common/queue-wrapper');
const LightningDomain = require('../../models/lightning-domain');
const logger = require('../../utilities/logger');
const { reviewAndSetStatusForDomain } = require('../../utilities/funnelDomainStatusUtility');
const axios = require('axios');

const processCb = async (job, done) => {
try {
let { domain } = job.data;

// Validate domain has cf_id
if (!domain.cf_id) {
logger.error({
initiator: 'QM/domains/cleanup',
message: 'Incorrect domain provided',
});
}

// Fetch current Cloudflare status
let newDomain = await axios.get(
`https://api.cloudflare.com/client/v4/zones/${process.env.LD_CLOUDFLARE_ZONE_ID}/custom_hostnames/${domain.cf_id}`,
{ headers: { Authorization: 'Bearer ' + process.env.CLOUDFLARE_API_KEY } },
);

// Handle orphaned domains (not found in Cloudflare)
if (newDomain.data?.success === false) {
// delete from db
await LightningDomain.deleteOne({ _id: domain._id });
await reviewAndSetStatusForDomain({ domain_id: domain._id });
done();
return;
} else {
newDomain = newDomain.data?.result;

// Sync status changes from Cloudflare
if (
newDomain &&
(domain.status != newDomain.status || domain.ssl.status != newDomain.ssl.status)
) {
await LightningDomain.updateOne({ _id: domain._id }, { ...newDomain });
if (newDomain.status != 'active') {
await reviewAndSetStatusForDomain({ domain_id: domain._id });
}
done();
return;
}
}

// Delete domains inactive for 14+ days
const nDaysAgo = new Date();
//setting to 7 days ago
nDaysAgo.setDate(nDaysAgo.getDate() - 14);

if (domain.created_at < nDaysAgo) {
//remove from db and cloudflare
let response = await axios.delete(
`https://api.cloudflare.com/client/v4/zones/${process.env.LD_CLOUDFLARE_ZONE_ID}/custom_hostnames/${domain.cf_id}`,
{
headers: {
Authorization: `Bearer ${process.env.CLOUDFLARE_API_KEY}`,
},
},
);
response = response.data;
if (response?.success) {
await LightningDomain.deleteOne({ _id: domain._id });
await reviewAndSetStatusForDomain({ domain_id: domain._id });
}
} else if (!domain.sent_idle_notification) {
// send notification (placeholder - not implemented)
}

done();
} catch (err) {
logger.error({
initiator: 'QM/domains/cleanup',
error: err,
api_error: err?.response?.data?.errors?.[0]?.message || undefined,
});
done(err);
}
};

let queue;

exports.start = async () => {
try {
if (!queue) queue = QueueWrapper(`domains_cleanup`, 'global', { processCb });
return Promise.resolve(queue)
.then(result => {
logger.log({
initiator: 'QM/queues/domains/cleanup',
message: 'Queue resolved:' + result,
});
return result;
})
.catch(error => {
logger.error({
initiator: 'QM/queues/domains/cleanup',
message: 'Error resolving queue:' + error,
});
throw error;
});
} catch (err) {
logger.log({
initiator: 'QM/queues/domains/cleanup',
message: 'Error while initializing domain validity queue:' + err.message,
error: err,
});
}
};

๐Ÿ—„๏ธ Collections Usedโ€‹

lightning_domainsโ€‹

  • Operations: Find (query inactive domains), Update (sync status from Cloudflare), Delete (remove orphaned/expired domains)
  • Model: shared/models/lightning-domain.js
  • Usage Context: Clean up failed or abandoned domain provisioning

Query Criteria (Inactive Domains):

{
$or: [
{ status: { $ne: 'active' } }, // Domain status not active
{ 'ssl.status': { $ne: 'active' } } // SSL status not active
],
created_at: { $lt: nDaysAgo } // Created over 7 days ago
}

Update Operation (Sync Status):

await LightningDomain.updateOne(
{ _id: domain._id },
{ ...newDomain }, // Spread Cloudflare domain object
);

Delete Operations:

// Orphaned domain (not in Cloudflare)
await LightningDomain.deleteOne({ _id: domain._id });

// Inactive for 14+ days
await LightningDomain.deleteOne({ _id: domain._id });

Key Fields:

  • status: Domain status ('active', 'pending', 'pending_validation', 'blocked')
  • ssl.status: SSL certificate status ('active', 'pending', 'pending_validation', 'failed')
  • created_at: Domain creation timestamp
  • cf_id: Cloudflare custom hostname ID
  • sent_idle_notification: Boolean flag for notification tracking (unused)

funnels (Indirect via Utility)โ€‹

  • Operations: Update (via reviewAndSetStatusForDomain utility)
  • Model: shared/models/funnel.js
  • Usage Context: Set funnels to test mode when domain is deleted

Utility Function: utilities/funnelDomainStatusUtility.js

Purpose: Updates all funnels using the deleted domain to prevent broken live funnels

๐Ÿ”ง Job Configurationโ€‹

Cron Scheduleโ€‹

'0 */6 * * *'; // Every 6 hours at minute 0 (12am, 6am, 12pm, 6pm)

Why 6-Hour Interval?

  • 7-14 day grace periods make frequent checks unnecessary
  • Balances cleanup with API usage
  • Low urgency (abandoned domains can wait)

Grace Periodsโ€‹

7-Day Grace Period (Service Query):

const nDaysAgo = new Date();
nDaysAgo.setDate(nDaysAgo.getDate() - 7);
  • Domains inactive for 7+ days are queued for cleanup
  • Allows time for SSL validation and DNS propagation

14-Day Grace Period (Processor Deletion):

const nDaysAgo = new Date();
nDaysAgo.setDate(nDaysAgo.getDate() - 14);
  • Domains inactive for 14+ days are permanently deleted
  • Additional 7-day buffer after initial cleanup check

Job Settingsโ€‹

queue.add(
{ domain }, // Full domain document
{
attempts: 3, // Retry up to 3 times
},
);

Job Data:

  • domain: Complete Lightning Domain document

Queue Configurationโ€‹

QueueWrapper(`domains_cleanup`, 'global', { processCb });

Queue Name: domains_cleanup

Redis Scope: global (shared across queue manager instances)

๐Ÿ“‹ Processing Logic - Detailed Flowโ€‹

1. Inactive Domain Identificationโ€‹

Query Logic:

{
$or: [
{ status: { $ne: 'active' } },
{ 'ssl.status': { $ne: 'active' } }
],
created_at: { $lt: nDaysAgo }
}

Inactive Statuses:

StatusMeaningAction
pendingDNS propagation in progressWait 7-14 days
pending_validationAwaiting domain verificationWait 7-14 days
blockedCloudflare blocked domainDelete after 14 days
movedDomain moved to another zoneDelete (orphaned)

SSL Statuses:

SSL StatusMeaningAction
pendingCertificate issuance in progressWait 7-14 days
pending_validationAwaiting domain validationWait 7-14 days
failedCertificate issuance failedDelete after 14 days

Why 7-Day Threshold?

  • SSL validation can take 1-3 days
  • DNS propagation can take 24-48 hours
  • 7 days provides generous buffer for legitimate delays

2. Cloudflare Status Verificationโ€‹

Fetch Current Status:

let newDomain = await axios.get(
`https://api.cloudflare.com/client/v4/zones/${process.env.LD_CLOUDFLARE_ZONE_ID}/custom_hostnames/${domain.cf_id}`,
{ headers: { Authorization: 'Bearer ' + process.env.CLOUDFLARE_API_KEY } },
);

Response Scenarios:

Success (Domain Found):

{
success: true,
result: {
id: 'cf123...',
hostname: 'custom.example.com',
status: 'active', // May have changed
ssl: {
status: 'active' // May have changed
}
}
}

Failure (Domain Not Found):

{
success: false,
errors: [
{
code: 1003,
message: 'custom hostname not found'
}
]
}

3. Orphaned Domain Handlingโ€‹

Detection:

if (newDomain.data?.success === false) {
// Domain not found in Cloudflare = orphaned record
}

Why Orphaned?

  • Domain deleted from Cloudflare manually
  • Cloudflare zone transferred/deleted
  • API sync issue during creation

Cleanup Action:

await LightningDomain.deleteOne({ _id: domain._id });
await reviewAndSetStatusForDomain({ domain_id: domain._id });

Why Delete Immediately?

  • No Cloudflare record = no way to resolve
  • Prevents database clutter
  • Updates affected funnels

4. Status Synchronizationโ€‹

Detect Status Changes:

if (newDomain && (domain.status != newDomain.status || domain.ssl.status != newDomain.ssl.status)) {
// Status changed since last check
}

Sync from Cloudflare:

await LightningDomain.updateOne({ _id: domain._id }, { ...newDomain });

Update Funnels if Still Inactive:

if (newDomain.status != 'active') {
await reviewAndSetStatusForDomain({ domain_id: domain._id });
}

Why Sync?

  • Domain may have become active since last validation job
  • Prevents premature deletion of domains in progress
  • Keeps database in sync with Cloudflare

5. 14-Day Deletion Logicโ€‹

Check Domain Age:

const nDaysAgo = new Date();
nDaysAgo.setDate(nDaysAgo.getDate() - 14);

if (domain.created_at < nDaysAgo) {
// Domain created 14+ days ago and still inactive = delete
}

Cloudflare Deletion:

let response = await axios.delete(
`https://api.cloudflare.com/client/v4/zones/${process.env.LD_CLOUDFLARE_ZONE_ID}/custom_hostnames/${domain.cf_id}`,
{ headers: { Authorization: `Bearer ${process.env.CLOUDFLARE_API_KEY}` } },
);

Database Deletion (Only if Cloudflare Deletion Succeeds):

if (response?.success) {
await LightningDomain.deleteOne({ _id: domain._id });
await reviewAndSetStatusForDomain({ domain_id: domain._id });
}

Why 14 Days?

  • Generous grace period for slow SSL validation
  • Allows manual intervention for edge cases
  • Prevents accidental deletion of in-progress domains

6. Idle Notification (Placeholder)โ€‹

Unimplemented Feature:

else if (!domain.sent_idle_notification) {
// send notification (placeholder - not implemented)
}

Intended Behavior:

  • Notify user domain is inactive (7-14 days)
  • Warn of impending deletion
  • Provide resolution steps

Current State: Comment only, no implementation.

๐Ÿšจ Error Handlingโ€‹

Common Error Scenariosโ€‹

Missing cf_idโ€‹

Scenario: Domain record without Cloudflare ID

Handling:

if (!domain.cf_id) {
logger.error({
initiator: 'QM/domains/cleanup',
message: 'Incorrect domain provided',
});
}

Result: Error logged, processing continues (no return statement - bug).

Impact: May cause Cloudflare API errors downstream.

Cloudflare API Errorsโ€‹

Domain Not Found (404):

Scenario: Orphaned domain already deleted from Cloudflare

Result: Database record deleted, funnels updated, job succeeds.

Rate Limit Exceeded:

Scenario: Too many API calls in short period

Result: Job fails, retries up to 3 times.

Database Errorsโ€‹

Connection Lost:

Scenario: MongoDB connection lost during deletion

Result: Exception thrown, job fails, retries up to 3 times.

Deletion Conflict:

Scenario: Domain already deleted by concurrent process

Result: deleteOne succeeds (0 documents deleted), no error.

No Retry Logic for Cloudflare Callsโ€‹

Unlike Cancel Job: No inline retry logic for Cloudflare API calls.

Bull Retries Only: Relies on Bull queue's 3-attempt retry mechanism.

Potential Issue: Transient Cloudflare errors may cause premature job failure.

๐Ÿ“Š Monitoring & Loggingโ€‹

Success Loggingโ€‹

Service-Level:

logger.log({
initiator: 'QM/domains/cleanup',
message: 'Domain Cleanup service processed.',
});

Queue Initialization:

logger.log({
initiator: 'QM/queues/domains/cleanup',
message: 'Queue resolved:' + result,
});

Error Loggingโ€‹

Service Query Errors:

logger.error({
initiator: 'QM/domains/cleanup',
message: 'Error fetching domains for cleanup',
error: err,
});

Processor Errors:

logger.error({
initiator: 'QM/domains/cleanup',
error: err,
api_error: err?.response?.data?.errors?.[0]?.message || undefined,
});

Missing cf_id:

logger.error({
initiator: 'QM/domains/cleanup',
message: 'Incorrect domain provided',
});

Performance Metricsโ€‹

  • Service Query Time: < 100ms (indexed queries)
  • Cloudflare API Latency: 200-500ms per request (GET + DELETE)
  • Job Processing Time: 1-3 seconds per domain
  • Typical Volume: 5-50 domains per run (varies by inactive domain accumulation)

๐Ÿ”— Integration Pointsโ€‹

Triggers This Jobโ€‹

  • Cron Schedule: Every 6 hours automatically
  • Manual Trigger: Via API endpoint (if QM_HOOKS=true)

External Dependenciesโ€‹

  • Cloudflare API: Custom Hostnames GET and DELETE endpoints
    • Zone ID: process.env.LD_CLOUDFLARE_ZONE_ID
    • API Key: process.env.CLOUDFLARE_API_KEY
    • Rate Limit: 1,200 requests per 5 minutes

Jobs That Depend On Thisโ€‹

  • Domain Validation: May re-validate domains cleaned up by this job
  • Domain Cancellation: Similar deletion logic (could be consolidated)

Utilities Usedโ€‹

  • reviewAndSetStatusForDomain: Updates funnel status when domain is deleted

โš ๏ธ Important Notesโ€‹

Side Effectsโ€‹

  • โš ๏ธ Permanent Deletion: Removes domains from Cloudflare AND database after 14 days
  • โš ๏ธ Orphaned Domain Cleanup: Immediately deletes domains not found in Cloudflare
  • โš ๏ธ Funnel Impact: Sets all funnels using deleted domains to test mode
  • โš ๏ธ Status Sync: Updates database with current Cloudflare status

Performance Considerationsโ€‹

  • 6-Hour Polling: Low frequency, suitable for cleanup tasks
  • No Batch Operations: Processes domains sequentially via queue
  • Indexed Queries: Ensure indexes on status, ssl.status, created_at
  • API Usage: 2 API calls per domain (GET + DELETE)

Business Logicโ€‹

Why Two Grace Periods?

  • 7 Days: Initial check for problematic domains
  • 14 Days: Final deletion threshold
  • Provides 7-day buffer for status sync and manual intervention

Why Delete Orphaned Domains Immediately?

  • No Cloudflare record = unrecoverable
  • Prevents database bloat
  • No user impact (domain already gone from Cloudflare)

Why Sync Status Before Deleting?

  • Domain may have become active since last validation
  • Prevents deletion of domains that resolved
  • Reduces false positives

Why No Notification Implementation?

  • Placeholder for future feature
  • Would warn users before deletion
  • Currently relying on grace periods only

Maintenance Notesโ€‹

  • Grace Periods: 7-day and 14-day thresholds hardcoded
  • Idle Notification: Not implemented (placeholder code exists)
  • Missing cf_id Handling: Incomplete (logs error but continues)
  • Database Indexes: Ensure composite index on (status, ssl.status, created_at)

Code Quality Issuesโ€‹

Bug: Missing cf_id Not Handled:

if (!domain.cf_id) {
logger.error({ message: 'Incorrect domain provided' });
}
// No return statement - processing continues with invalid domain

Impact: Cloudflare API call will fail with null cf_id.

Fix:

if (!domain.cf_id) {
logger.error({ message: 'Incorrect domain provided' });
done(new Error('Missing cf_id'));
return;
}

Bug: Comment Mismatch:

const nDaysAgo = new Date();
//setting to 7 days ago
nDaysAgo.setDate(nDaysAgo.getDate() - 14); // Actually 14 days

Impact: Confusing comment, but logic is correct.

๐Ÿงช Testingโ€‹

Manual Triggerโ€‹

# Via API (if QM_HOOKS=true)
POST http://localhost:6002/api/trigger/domains/cleanup

Simulate Orphaned Domainโ€‹

// Create domain in database without Cloudflare record
const domain = await LightningDomain.create({
hostname: 'orphaned.example.com',
cf_id: 'nonexistent-cf-id',
status: 'pending',
ssl: { status: 'pending' },
created_at: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000), // 8 days ago
});

// Trigger cleanup
await cleanup();

// Verify deletion
const deleted = await LightningDomain.findById(domain._id);
console.log('Orphaned domain deleted:', !deleted); // Should be true

Simulate Status Changeโ€‹

// Create inactive domain
const domain = await LightningDomain.create({
hostname: 'test.example.com',
cf_id: 'valid-cf-id',
status: 'pending',
ssl: { status: 'pending' },
created_at: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000),
});

// Manually activate domain in Cloudflare (use Cloudflare dashboard or API)

// Trigger cleanup
await cleanup();

// Verify status synced (not deleted)
const synced = await LightningDomain.findById(domain._id);
console.log('Status synced:', synced.status); // Should be 'active'
console.log('Domain preserved:', !!synced); // Should be true

Test 14-Day Deletionโ€‹

// Create old inactive domain
const oldDomain = await LightningDomain.create({
hostname: 'old.example.com',
cf_id: 'old-cf-id',
status: 'pending',
ssl: { status: 'pending' },
created_at: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000), // 15 days ago
});

// Trigger cleanup
await cleanup();

// Verify deletion
const deleted = await LightningDomain.findById(oldDomain._id);
console.log('Old domain deleted:', !deleted); // Should be true

Monitor Cleanup Activityโ€‹

// Count domains eligible for cleanup
const nDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
const eligibleCount = await LightningDomain.countDocuments({
$or: [{ status: { $ne: 'active' } }, { 'ssl.status': { $ne: 'active' } }],
created_at: { $lt: nDaysAgo },
});

console.log(`${eligibleCount} domains eligible for cleanup`);

// Count domains to be deleted (14+ days)
const deletionThreshold = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000);
const deletionCount = await LightningDomain.countDocuments({
$or: [{ status: { $ne: 'active' } }, { 'ssl.status': { $ne: 'active' } }],
created_at: { $lt: deletionThreshold },
});

console.log(`${deletionCount} domains marked for deletion`);

Verify Funnel Status Updateโ€‹

// Setup: Create funnel with inactive domain
const domain = await LightningDomain.create({
hostname: 'test.example.com',
cf_id: 'test-cf-id',
status: 'pending',
created_at: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000),
});

const funnel = await Funnel.create({
name: 'Test Funnel',
domain_id: domain._id,
status: 'live',
});

// Trigger cleanup (should delete domain)
await cleanup();

// Verify funnel set to test mode
const updatedFunnel = await Funnel.findById(funnel._id);
console.log('Funnel status:', updatedFunnel.status); // Should be 'test'

Test Cloudflare Syncโ€‹

// Find domain with status mismatch
const domain = await LightningDomain.findOne({
status: 'pending',
created_at: { $lt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) },
});

// Check current Cloudflare status
const cfDomain = await axios.get(
`https://api.cloudflare.com/client/v4/zones/${process.env.LD_CLOUDFLARE_ZONE_ID}/custom_hostnames/${domain.cf_id}`,
{ headers: { Authorization: 'Bearer ' + process.env.CLOUDFLARE_API_KEY } },
);

console.log('DB status:', domain.status);
console.log('CF status:', cfDomain.data.result.status);
console.log('Mismatch:', domain.status !== cfDomain.data.result.status);

// Trigger cleanup
await cleanup();

// Verify sync
const updated = await LightningDomain.findById(domain._id);
console.log('Status synced:', updated.status === cfDomain.data.result.status);

Job Type: Scheduled + Queued
Execution Frequency: Every 6 hours
Average Duration: 1-3 seconds per domain
Status: Active

๐Ÿ’ฌ

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM