pro
Advanced Usage
Events, permissions, and troubleshooting for Sync.
- Events
- sync.push.finished
- sync.pull.finished
- sync.item.pushed
- Permissions
- Role Configuration
- Troubleshooting
- Sync Not Starting
- Connection Errors
- Assets Not Transferring
- Sync Lock Issues
- Data Conflicts
- Debugging
- Performance Optimization
- Large Dataset Handling
- Asset Sync Optimization
- Timeout Configuration
- Security Considerations
- Key Rotation
- Network Security
- Audit Logging
- Custom Sync Handlers
- Pre-Sync Hook
- Post-Sync Hook
- Monitoring
- Sync Status API
- Health Check
Events
sync.push.finished
Triggered after a push sync completes:
$app->on('sync.push.finished', function($target) {
// Notify team
$this->mailer->mail(
'team@example.com',
'Content pushed to ' . $target['uri'],
'Sync completed successfully.'
);
// Clear caches
$this->helper('cache')->flush();
});
sync.pull.finished
Triggered after a pull sync completes:
$app->on('sync.pull.finished', function($target) {
// Rebuild search index
$this->module('detektivo')->index();
// Log the sync
$this->module('system')->log(
"Pulled data from {$target['uri']}",
channel: 'sync',
type: 'info'
);
});
sync.item.pushed
Triggered when an individual item is synced:
$app->on('sync.item.pushed', function($type, $target, $item) {
// Log individual item syncs
$this->module('system')->log(
"Synced {$type} item {$item['_id']} to {$target['uri']}",
channel: 'sync',
type: 'info'
);
});
Permissions
| Permission | Description |
|---|---|
sync/manage |
Full access to sync configuration and execution |
Role Configuration
// Only administrators should have sync access
[
'name' => 'Administrator',
'permissions' => [
'sync/manage' => true
]
]
// Content editors typically don't need sync access
[
'name' => 'Editor',
'permissions' => [
'sync/manage' => false
]
]
Troubleshooting
Sync Not Starting
- Check that a sync job isn't already running
- Verify the target URL is accessible
- Confirm sync keys match on both ends
- Check server logs for errors
Connection Errors
- Verify target server is reachable
- Check firewall rules allow connections
- Ensure HTTPS certificates are valid
- Test with curl:
curl -X POST https://target/api/sync/check \
-H "Content-Type: application/json" \
-d '{"syncKey": "your-key"}'
Assets Not Transferring
- Verify both servers can access each other's uploads
- Check file permissions on upload directories
- Ensure upload URLs are publicly accessible
- Large files may timeout - consider increasing limits
Sync Lock Issues
If sync appears stuck, reset the lock:
- Go to Settings > Sync
- Click Reset to clear the lock file
Or manually remove: /storage/tmp/sync.lock
Data Conflicts
- Sync uses IDs to match records - same IDs will be updated
- Mirror mode will remove data not in the source
- Use "Missing Keys Only" for translations to preserve edits
Debugging
Enable verbose logging:
// config/config.php
return [
'debug' => true,
'sync' => [
'syncKey' => '...'
]
];
Check sync logs at Settings > System > Logs filtered by channel: sync
Performance Optimization
Large Dataset Handling
For datasets with thousands of items:
// Batch sync by model
$models = ['posts', 'products', 'pages'];
foreach ($models as $model) {
$jobs = [
[
'name' => 'content',
'syncSettings' => [
'models' => [$model],
'batchSize' => 100
]
]
];
Cockpit()->helper('sync')->run($target, $jobs);
// Allow some delay between batches
sleep(2);
}
Asset Sync Optimization
For large media libraries:
// Sync only recently modified assets
$jobs = [
[
'name' => 'assets',
'syncSettings' => [
'modifiedSince' => strtotime('-7 days'),
'skipLargeFiles' => true,
'maxFileSize' => 10 * 1024 * 1024 // 10MB
]
]
];
Timeout Configuration
Adjust PHP timeout for large syncs:
// In sync script
set_time_limit(3600); // 1 hour
ini_set('memory_limit', '512M');
Security Considerations
Key Rotation
Periodically rotate sync keys:
- Generate new key on target server
- Update target configuration with new key
- Test connectivity
- Remove old key
Network Security
// Restrict sync to specific IPs
$app->on('sync.request.before', function() {
$allowedIPs = ['192.168.1.100', '10.0.0.50'];
if (!in_array($_SERVER['REMOTE_ADDR'], $allowedIPs)) {
throw new \Exception('Sync request from unauthorized IP');
}
});
Audit Logging
Log all sync operations:
$app->on('sync.push.finished', function($target) use ($app) {
$app->dataStorage->save('sync/audit_log', [
'action' => 'push',
'target' => $target['uri'],
'user' => $app->helper('auth')->getUser()['user'] ?? 'system',
'timestamp' => time(),
'ip' => $_SERVER['REMOTE_ADDR'] ?? null
]);
});
Custom Sync Handlers
Pre-Sync Hook
Modify data before sync:
$app->on('sync.content.before', function(&$items) {
foreach ($items as &$item) {
// Strip internal fields
unset($item['_internalNotes']);
// Transform data for production
if (isset($item['debugMode'])) {
$item['debugMode'] = false;
}
}
});
Post-Sync Hook
Actions after sync completes:
$app->on('sync.content.after', function($items, $target) use ($app) {
// Trigger cache invalidation on target
$app->helper('async')->run(function() use ($target) {
file_get_contents("{$target['uri']}/api/cache/clear");
});
});
Monitoring
Sync Status API
Create an endpoint to check sync status:
// config/api/sync-status.php
return function() {
$lockFile = $this->path('#tmp:') . '/sync.lock';
return [
'syncing' => file_exists($lockFile),
'lastSync' => $this->dataStorage->findOne('sync/log', [
'sort' => ['timestamp' => -1]
])
];
};
Health Check
Monitor sync connectivity:
// health-check.php
$targets = [
['name' => 'Production', 'uri' => 'https://cms.example.com'],
['name' => 'Staging', 'uri' => 'https://staging.example.com'],
];
foreach ($targets as $target) {
$response = @file_get_contents("{$target['uri']}/api/sync/check");
if ($response && json_decode($response)->success) {
echo "â
{$target['name']}: Connected\n";
} else {
echo "â {$target['name']}: Unreachable\n";
}
}