BeepSyncManager
Schema-driven synchronization manager for one-way and bidirectional sync workflows.
- Primary implementation:
DataManagementEngineStandard/Editor/BeepSync/BeepSyncManager.Core.cs. - Use
SyncSchemas,SyncDataAsync(...),LastRunConflicts, andLastRunCheckpointas current runtime surfaces. - If a snippet below uses legacy naming, prefer the BeepSyncManager APIs shown in the "Current Implementation Pattern" section.
Table of Contents
Overview
The BeepSyncManager is the synchronization orchestration component in the current
engine. It executes schema-driven sync operations and keeps run metadata for conflicts and checkpoints.
It integrates with import and mapping surfaces while exposing a focused sync API.
BeepSyncManager provides one-way and bidirectional synchronization with conflict tracking and resumable checkpoint-aware execution.
Signature-Verified Snapshot (BeepSync)
public partial class BeepSyncManager : IDisposable
{
public SyncIntegrationContext IntegrationContext { get; set; }
public List<ConflictEvidence> LastRunConflicts { get; private set; }
public SyncCheckpoint LastRunCheckpoint { get; private set; }
public SyncReconciliationReport LastRunReconciliationReport { get; private set; }
public ObservableBindingList<DataSyncSchema> SyncSchemas { get; set; }
public BeepSyncManager(IDMEEditor editor);
public BeepSyncManager(IDMEEditor editor, SyncIntegrationContext integrationContext);
public void AddSyncSchema(DataSyncSchema schema);
public Task<IErrorsInfo> SyncDataAsync(
DataSyncSchema schema,
IProgress<PassedArgs> progress = null,
CancellationToken cancellationToken = default);
public void SyncData(DataSyncSchema schema);
}
Bidirectional Sync
Two-way data synchronization between multiple systems
? Real-time Processing
Change detection and immediate synchronization capabilities
Conflict Resolution
Intelligent conflict detection and resolution strategies
Comprehensive Monitoring
Detailed logging, progress tracking, and sync analytics
Sync Architecture
| Component | Role in Synchronization | Key Features |
|---|---|---|
| ETL Editor | Schema synchronization and bulk operations | Entity creation, structure validation, batch processing |
| Data Import Manager | Incremental data synchronization | Async imports, progress tracking, transformation |
| Mapping Manager | Data transformation and field mapping | Object mapping, type conversion, relationship handling |
| Defaults Manager | Consistent data population | Rule-based defaults, static values, audit fields |
| DMEEditor | Coordination and resource management | Data source management, logging, configuration |
- Modular Design: Each component handles specific aspects of synchronization
- Reusable Components: Same components used for different sync scenarios
- Scalable Processing: Async operations and batch processing for performance
- Extensible Framework: Easy to add new sync strategies and transformations
Current Implementation Pattern
// DataManagementEngineStandard/Editor/BeepSync/BeepSyncManager.Core.cs
var manager = new BeepSyncManager(dmeEditor);
// SyncSchemas contains the configured sync definitions
foreach (var schema in manager.SyncSchemas)
{
// Execute schema-driven synchronization
var result = await manager.SyncDataAsync(schema, cancellationToken);
}
// Run metadata surfaces
var conflicts = manager.LastRunConflicts;
var checkpoint = manager.LastRunCheckpoint;
Synchronization Strategies
Complete data synchronization using ETL Editor for comprehensive data migration:
- Schema Sync: Ensure destination schema matches source requirements
- Data Migration: Transfer all data with validation and transformation
- Relationship Preservation: Maintain referential integrity during sync
- Validation: Comprehensive data validation and error reporting
Efficient synchronization of only changed data using Data Import Manager:
- Change Detection: Identify modified records since last sync
- Delta Processing: Process only changed records
- Timestamp Tracking: Use modification timestamps for change detection
- Conflict Detection: Identify potential data conflicts
Two-way synchronization with conflict resolution:
- Master-Master Sync: Handle changes from multiple sources
- Conflict Resolution: Automated and manual conflict resolution strategies
- Change Vectors: Track change direction and precedence
- Rollback Support: Ability to rollback synchronization changes
Sync Strategy Implementation
public enum SyncStrategy
{
FullSync,
IncrementalSync,
BidirectionalSync,
RealTimeSync
}
public class SyncConfiguration
{
public SyncStrategy Strategy { get; set; }
public string SourceDataSourceName { get; set; }
public string DestinationDataSourceName { get; set; }
public List<string> EntitiesToSync { get; set; }
public Dictionary<string, EntityDataMap> EntityMappings { get; set; }
public ConflictResolutionStrategy ConflictResolution { get; set; }
public TimeSpan SyncInterval { get; set; }
public DateTime LastSyncTime { get; set; }
public bool EnableRealTimeSync { get; set; }
}
public async Task<SyncResult> ExecuteSync(SyncConfiguration config)
{
CurrentStatus = SyncStatus.Running;
var syncResult = new SyncResult { StartTime = DateTime.Now };
try
{
switch (config.Strategy)
{
case SyncStrategy.FullSync:
syncResult = await ExecuteFullSync(config);
break;
case SyncStrategy.IncrementalSync:
syncResult = await ExecuteIncrementalSync(config);
break;
case SyncStrategy.BidirectionalSync:
syncResult = await ExecuteBidirectionalSync(config);
break;
case SyncStrategy.RealTimeSync:
syncResult = await ExecuteRealTimeSync(config);
break;
}
syncResult.EndTime = DateTime.Now;
syncResult.Duration = syncResult.EndTime - syncResult.StartTime;
// Log sync completion
SyncHistory.Add(new SyncLog
{
Timestamp = DateTime.Now,
Strategy = config.Strategy,
Result = syncResult,
Message = $"Sync completed: {syncResult.RecordsProcessed} records processed"
});
SyncCompleted?.Invoke(this, new SyncCompleteEventArgs(syncResult));
return syncResult;
}
catch (Exception ex)
{
syncResult.Success = false;
syncResult.ErrorMessage = ex.Message;
ErrorOccurred?.Invoke(this, new SyncErrorEventArgs(ex, config));
return syncResult;
}
finally
{
CurrentStatus = SyncStatus.Idle;
}
}
Component Integration
Full Synchronization Implementation
private async Task<SyncResult> ExecuteFullSync(SyncConfiguration config)
{
var result = new SyncResult();
var progress = new Progress<PassedArgs>(args =>
{
ProgressUpdated?.Invoke(this, new SyncProgressEventArgs
{
CurrentEntity = args.CurrentEntity,
ProcessedRecords = args.ParameterInt1,
TotalRecords = args.ParameterInt2,
Message = args.Messege
});
});
using var cancellationTokenSource = new CancellationTokenSource();
try
{
// Step 1: Prepare data sources
var sourceDs = _dmeEditor.GetDataSource(config.SourceDataSourceName);
var destDs = _dmeEditor.GetDataSource(config.DestinationDataSourceName);
_dmeEditor.OpenDataSource(config.SourceDataSourceName);
_dmeEditor.OpenDataSource(config.DestinationDataSourceName);
// Step 2: Create comprehensive ETL script
_etlEditor.CreateScriptHeader(sourceDs, progress, cancellationTokenSource.Token);
// Step 3: Filter entities if specified
if (config.EntitiesToSync?.Any() == true)
{
_etlEditor.Script.ScriptDetails = _etlEditor.Script.ScriptDetails
.Where(s => config.EntitiesToSync.Contains(s.SourceEntityName))
.ToList();
}
// Step 4: Apply entity mappings if configured
foreach (var mapping in config.EntityMappings ?? new Dictionary<string, EntityDataMap>())
{
ApplyMappingToETLScript(mapping.Key, mapping.Value);
}
// Step 5: Execute ETL script
var etlResult = await _etlEditor.RunCreateScript(
progress, cancellationTokenSource.Token, copydata: true, useEntityStructure: true);
result.Success = etlResult.Flag == Errors.Ok;
result.ErrorMessage = etlResult.Message;
result.RecordsProcessed = _etlEditor.CurrentScriptRecord;
// Step 6: Collect detailed logs
result.DetailedLogs = _etlEditor.LoadDataLogs
.Select(log => log.InputLine)
.ToList();
return result;
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = ex.Message;
return result;
}
finally
{
_dmeEditor.CloseDataSource(config.SourceDataSourceName);
_dmeEditor.CloseDataSource(config.DestinationDataSourceName);
}
}
Incremental Synchronization Implementation
private async Task<SyncResult> ExecuteIncrementalSync(SyncConfiguration config)
{
var result = new SyncResult();
var totalProcessed = 0;
try
{
foreach (var entityName in config.EntitiesToSync)
{
var importManager = new DataImportManager(_dmeEditor);
// Configure import manager for incremental sync
importManager.SourceEntityName = entityName;
importManager.SourceDataSourceName = config.SourceDataSourceName;
importManager.DestEntityName = entityName;
importManager.DestDataSourceName = config.DestinationDataSourceName;
// Load destination structure
var structureResult = importManager.LoadDestEntityStructure(
entityName, config.DestinationDataSourceName);
if (structureResult.Flag != Errors.Ok)
{
result.ErrorMessage += $"Failed to load structure for {entityName}: {structureResult.Message}\n";
continue;
}
// Configure incremental filters
ConfigureIncrementalFilters(importManager, config.LastSyncTime);
// Apply entity mapping if configured
if (config.EntityMappings?.ContainsKey(entityName) == true)
{
importManager.Mapping = config.EntityMappings[entityName];
}
// Set up progress tracking
var progress = new Progress<IPassedArgs>(args =>
{
ProgressUpdated?.Invoke(this, new SyncProgressEventArgs
{
CurrentEntity = entityName,
ProcessedRecords = args.ParameterInt1,
Message = args.Messege
});
});
// Execute incremental import
using var cancellationTokenSource = new CancellationTokenSource();
var importResult = await importManager.RunImportAsync(
progress, cancellationTokenSource.Token,
transformation: ApplyBusinessRules, batchSize: 100);
if (importResult.Flag == Errors.Ok)
{
var processedCount = importManager.ImportLogData?.Count ?? 0;
totalProcessed += processedCount;
result.EntityResults[entityName] = new EntitySyncResult
{
Success = true,
RecordsProcessed = processedCount,
Message = $"Successfully synced {processedCount} records"
};
}
else
{
result.EntityResults[entityName] = new EntitySyncResult
{
Success = false,
Message = importResult.Message
};
}
}
result.Success = result.EntityResults.Values.All(r => r.Success);
result.RecordsProcessed = totalProcessed;
// Update last sync time if successful
if (result.Success)
{
config.LastSyncTime = DateTime.Now;
}
return result;
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = ex.Message;
return result;
}
}
private void ConfigureIncrementalFilters(DataImportManager importManager, DateTime lastSyncTime)
{
// Add filter for records modified since last sync
importManager.SourceFilters.Add(new AppFilter
{
FieldName = "ModifiedDate",
Operator = ">=",
FilterValue = lastSyncTime.ToString("yyyy-MM-dd HH:mm:ss")
});
// You can add additional filters based on your requirements
// For example, only sync active records:
importManager.SourceFilters.Add(new AppFilter
{
FieldName = "IsActive",
Operator = "=",
FilterValue = "true"
});
}
private object ApplyBusinessRules(object record)
{
// Apply business transformation rules
// This could include data validation, cleansing, enrichment, etc.
// Example: Apply defaults for audit fields
if (record is Dictionary<string, object> dict)
{
// Apply sync-specific metadata
dict["LastSyncDate"] = DateTime.Now;
dict["SyncSource"] = "DataSyncManager";
// Apply any business rules or transformations
// based on your specific requirements
}
return record;
}
Conflict Resolution
| Strategy | Description | Use Case |
|---|---|---|
| SourceWins | Source data always takes precedence | Master-slave replication |
| DestinationWins | Destination data is preserved | Local data protection |
| TimestampBased | Most recent change wins | Concurrent editing scenarios |
| ManualResolution | Flag conflicts for manual review | Critical data integrity |
| FieldLevel | Resolve conflicts at field level | Granular conflict handling |
| BusinessRules | Custom business logic determines winner | Complex business scenarios |
- Timestamp precision and time zone differences
- Partial record updates vs. full record synchronization
- Cascading changes in related entities
- Data type conversion conflicts
Conflict Resolution Implementation
public enum ConflictResolutionStrategy
{
SourceWins,
DestinationWins,
TimestampBased,
ManualResolution,
FieldLevel,
BusinessRules
}
public class ConflictResolver
{
private readonly IDMEEditor _dmeEditor;
private readonly List<DataConflict> _pendingConflicts;
public ConflictResolver(IDMEEditor dmeEditor)
{
_dmeEditor = dmeEditor;
_pendingConflicts = new List<DataConflict>();
}
public ConflictResolutionResult ResolveConflict(
DataConflict conflict,
ConflictResolutionStrategy strategy)
{
var result = new ConflictResolutionResult
{
ConflictId = conflict.Id,
Strategy = strategy,
Timestamp = DateTime.Now
};
try
{
switch (strategy)
{
case ConflictResolutionStrategy.SourceWins:
result.ResolvedData = conflict.SourceData;
result.Resolution = "Source data selected";
break;
case ConflictResolutionStrategy.DestinationWins:
result.ResolvedData = conflict.DestinationData;
result.Resolution = "Destination data preserved";
break;
case ConflictResolutionStrategy.TimestampBased:
result = ResolveByTimestamp(conflict);
break;
case ConflictResolutionStrategy.FieldLevel:
result = ResolveFieldLevel(conflict);
break;
case ConflictResolutionStrategy.BusinessRules:
result = ResolveByBusinessRules(conflict);
break;
case ConflictResolutionStrategy.ManualResolution:
_pendingConflicts.Add(conflict);
result.RequiresManualIntervention = true;
result.Resolution = "Flagged for manual resolution";
break;
}
result.Success = !result.RequiresManualIntervention;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.ErrorMessage = ex.Message;
return result;
}
}
private ConflictResolutionResult ResolveByTimestamp(DataConflict conflict)
{
var result = new ConflictResolutionResult();
var sourceTimestamp = GetTimestamp(conflict.SourceData);
var destTimestamp = GetTimestamp(conflict.DestinationData);
if (sourceTimestamp > destTimestamp)
{
result.ResolvedData = conflict.SourceData;
result.Resolution = $"Source data is newer ({sourceTimestamp})";
}
else
{
result.ResolvedData = conflict.DestinationData;
result.Resolution = $"Destination data is newer ({destTimestamp})";
}
return result;
}
private ConflictResolutionResult ResolveFieldLevel(DataConflict conflict)
{
var result = new ConflictResolutionResult();
var resolvedData = new Dictionary<string, object>();
var resolutionDetails = new List<string>();
// Compare each field and resolve individually
var sourceDict = ConvertToDict(conflict.SourceData);
var destDict = ConvertToDict(conflict.DestinationData);
var allFields = sourceDict.Keys.Union(destDict.Keys);
foreach (var field in allFields)
{
var sourceValue = sourceDict.ContainsKey(field) ? sourceDict[field] : null;
var destValue = destDict.ContainsKey(field) ? destDict[field] : null;
if (Equals(sourceValue, destValue))
{
resolvedData[field] = sourceValue;
resolutionDetails.Add($"{field}: No conflict");
}
else
{
// Apply field-specific resolution logic
var fieldResolution = ResolveFieldConflict(field, sourceValue, destValue);
resolvedData[field] = fieldResolution.Value;
resolutionDetails.Add($"{field}: {fieldResolution.Reason}");
}
}
result.ResolvedData = resolvedData;
result.Resolution = string.Join("; ", resolutionDetails);
return result;
}
private FieldResolution ResolveFieldConflict(string FieldName, object sourceValue, object destValue)
{
// Implement field-specific resolution logic
// This could be based on business rules, data types, etc.
// Example business rules:
if (FieldName.EndsWith("Date") || FieldName.EndsWith("Timestamp"))
{
// For date fields, use the most recent
if (sourceValue is DateTime sourceDate && destValue is DateTime destDate)
{
return sourceDate > destDate
? new FieldResolution { Value = sourceValue, Reason = "More recent date" }
: new FieldResolution { Value = destValue, Reason = "More recent date" };
}
}
if (FieldName.Contains("Amount") || FieldName.Contains("Price"))
{
// For monetary fields, might want to use the higher value or apply specific business logic
// This is just an example - real logic would depend on business requirements
}
// Default to source value
return new FieldResolution { Value = sourceValue, Reason = "Default to source" };
}
private ConflictResolutionResult ResolveByBusinessRules(DataConflict conflict)
{
// Implement custom business rules for conflict resolution
// This would integrate with your business rule engine
var result = new ConflictResolutionResult();
// Example business rule: Customer data conflicts
if (conflict.EntityName == "Customers")
{
result = ResolveCustomerConflict(conflict);
}
else if (conflict.EntityName == "Orders")
{
result = ResolveOrderConflict(conflict);
}
else
{
// Default resolution strategy
result.ResolvedData = conflict.SourceData;
result.Resolution = "Applied default business rule (source wins)";
}
return result;
}
private DateTime GetTimestamp(object data)
{
// Extract timestamp from data object
// This would depend on your data structure
if (data is Dictionary<string, object> dict)
{
if (dict.ContainsKey("ModifiedDate") && dict["ModifiedDate"] is DateTime modifiedDate)
return modifiedDate;
if (dict.ContainsKey("Timestamp") && dict["Timestamp"] is DateTime timestamp)
return timestamp;
}
return DateTime.MinValue;
}
}
public class DataConflict
{
public string Id { get; set; }
public string EntityName { get; set; }
public string KeyField { get; set; }
public object KeyValue { get; set; }
public object SourceData { get; set; }
public object DestinationData { get; set; }
public List<string> ConflictingFields { get; set; }
public DateTime DetectedAt { get; set; }
}
public class ConflictResolutionResult
{
public string ConflictId { get; set; }
public bool Success { get; set; }
public object ResolvedData { get; set; }
public string Resolution { get; set; }
public ConflictResolutionStrategy Strategy { get; set; }
public bool RequiresManualIntervention { get; set; }
public string ErrorMessage { get; set; }
public DateTime Timestamp { get; set; }
}
Monitoring & Logging
- Real-time Progress: Live updates on sync progress and performance
- Detailed Logging: Comprehensive operation logs with timestamps and context
- Error Tracking: Detailed error information and resolution suggestions
- Performance Metrics: Throughput, latency, and resource utilization tracking
- Audit Trails: Complete history of all synchronization operations
- Alerting: Configurable alerts for failures and performance issues
Monitoring and Logging Implementation
public class SyncMonitor
{
private readonly IDMEEditor _dmeEditor;
private readonly List<SyncMetric> _metrics;
private readonly Timer _metricsTimer;
public SyncMonitor(IDMEEditor dmeEditor)
{
_dmeEditor = dmeEditor;
_metrics = new List<SyncMetric>();
// Set up periodic metrics collection
_metricsTimer = new Timer(CollectMetrics, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
}
public void LogSyncStart(SyncConfiguration config)
{
var logEntry = new SyncLogEntry
{
Timestamp = DateTime.Now,
EventType = SyncEventType.SyncStarted,
Configuration = config,
Message = $"Starting {config.Strategy} sync from {config.SourceDataSourceName} to {config.DestinationDataSourceName}"
};
_dmeEditor.AddLogMessage("SyncManager", logEntry.Message, DateTime.Now, 0, null, Errors.Ok);
// Also log to specialized sync log
WriteSyncLog(logEntry);
}
public void LogSyncProgress(string entityName, int processed, int total, TimeSpan elapsed)
{
var throughput = processed / elapsed.TotalSeconds;
var logEntry = new SyncLogEntry
{
Timestamp = DateTime.Now,
EventType = SyncEventType.Progress,
EntityName = entityName,
RecordsProcessed = processed,
TotalRecords = total,
Throughput = throughput,
Message = $"Progress: {processed}/{total} records processed for {entityName} (Rate: {throughput:F1} records/sec)"
};
_dmeEditor.AddLogMessage("SyncProgress", logEntry.Message, DateTime.Now, processed, entityName, Errors.Ok);
WriteSyncLog(logEntry);
// Update metrics
UpdateMetrics(entityName, processed, throughput);
}
public void LogSyncCompletion(SyncResult result)
{
var logEntry = new SyncLogEntry
{
Timestamp = DateTime.Now,
EventType = result.Success ? SyncEventType.SyncCompleted : SyncEventType.SyncFailed,
RecordsProcessed = result.RecordsProcessed,
Duration = result.Duration,
Success = result.Success,
ErrorMessage = result.ErrorMessage,
Message = result.Success
? $"Sync completed successfully: {result.RecordsProcessed} records in {result.Duration.TotalMinutes:F1} minutes"
: $"Sync failed: {result.ErrorMessage}"
};
var errorFlag = result.Success ? Errors.Ok : Errors.Failed;
_dmeEditor.AddLogMessage("SyncManager", logEntry.Message, DateTime.Now, result.RecordsProcessed, null, errorFlag);
WriteSyncLog(logEntry);
// Generate summary metrics
GenerateSyncSummary(result);
}
public void LogConflictResolution(DataConflict conflict, ConflictResolutionResult resolution)
{
var logEntry = new SyncLogEntry
{
Timestamp = DateTime.Now,
EventType = SyncEventType.ConflictResolved,
EntityName = conflict.EntityName,
Message = $"Conflict resolved for {conflict.EntityName} key {conflict.KeyValue}: {resolution.Resolution}"
};
_dmeEditor.AddLogMessage("ConflictResolution", logEntry.Message, DateTime.Now, 0, conflict.EntityName, Errors.Ok);
WriteSyncLog(logEntry);
}
private void UpdateMetrics(string entityName, int processed, double throughput)
{
var metric = new SyncMetric
{
Timestamp = DateTime.Now,
EntityName = entityName,
RecordsProcessed = processed,
Throughput = throughput,
MemoryUsage = GC.GetTotalMemory(false)
};
_metrics.Add(metric);
// Keep only recent metrics to manage memory
if (_metrics.Count > 10000)
{
_metrics.RemoveRange(0, 1000);
}
}
private void CollectMetrics(object state)
{
// Collect system metrics
var systemMetric = new SystemMetric
{
Timestamp = DateTime.Now,
CpuUsage = GetCpuUsage(),
MemoryUsage = GC.GetTotalMemory(false),
ActiveSyncOperations = GetActiveSyncCount()
};
// Log system metrics
_dmeEditor.AddLogMessage("SystemMetrics",
$"CPU: {systemMetric.CpuUsage:F1}%, Memory: {systemMetric.MemoryUsage / 1024 / 1024:F1}MB, Active Syncs: {systemMetric.ActiveSyncOperations}",
DateTime.Now, 0, null, Errors.Ok);
}
private void GenerateSyncSummary(SyncResult result)
{
var summary = new SyncSummary
{
Timestamp = DateTime.Now,
Duration = result.Duration,
RecordsProcessed = result.RecordsProcessed,
Success = result.Success,
ThroughputAverage = result.RecordsProcessed / result.Duration.TotalSeconds,
EntityResults = result.EntityResults
};
// Generate summary report
var summaryMessage = $"""
Sync Summary:
- Duration: {summary.Duration.TotalMinutes:F1} minutes
- Records Processed: {summary.RecordsProcessed:N0}
- Average Throughput: {summary.ThroughputAverage:F1} records/second
- Success Rate: {(summary.Success ? "100%" : "Failed")}
- Entities Processed: {summary.EntityResults.Count}
""";
_dmeEditor.AddLogMessage("SyncSummary", summaryMessage, DateTime.Now, summary.RecordsProcessed, null, Errors.Ok);
}
public List<SyncMetric> GetRecentMetrics(TimeSpan period)
{
var cutoff = DateTime.Now - period;
return _metrics.Where(m => m.Timestamp >= cutoff).ToList();
}
public SyncHealthReport GenerateHealthReport()
{
var recentMetrics = GetRecentMetrics(TimeSpan.FromHours(24));
return new SyncHealthReport
{
GeneratedAt = DateTime.Now,
AverageThroughput = recentMetrics.Average(m => m.Throughput),
TotalRecordsProcessed = recentMetrics.Sum(m => m.RecordsProcessed),
ErrorRate = CalculateErrorRate(recentMetrics),
SystemHealth = AssessSystemHealth(),
Recommendations = GenerateRecommendations(recentMetrics)
};
}
}
// Supporting classes for monitoring
public class SyncLogEntry
{
public DateTime Timestamp { get; set; }
public SyncEventType EventType { get; set; }
public string EntityName { get; set; }
public int RecordsProcessed { get; set; }
public int TotalRecords { get; set; }
public double Throughput { get; set; }
public TimeSpan Duration { get; set; }
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public string Message { get; set; }
public SyncConfiguration Configuration { get; set; }
}
public enum SyncEventType
{
SyncStarted,
Progress,
ConflictDetected,
ConflictResolved,
EntityCompleted,
SyncCompleted,
SyncFailed,
Warning,
Error
}
Usage Examples
Complete Sync Manager Implementation
// Example usage of the complete Data Sync Manager
public class SyncManagerExample
{
public static async Task Main(string[] args)
{
// Initialize DME Editor using Autofac
var dmeEditor = InitializeDMEEditor();
// Create sync manager
var syncManager = new DataSyncManager(dmeEditor);
var monitor = new SyncMonitor(dmeEditor);
// Configure synchronization
var config = new SyncConfiguration
{
Strategy = SyncStrategy.IncrementalSync,
SourceDataSourceName = "SourceCRM",
DestinationDataSourceName = "DataWarehouse",
EntitiesToSync = new List<string> { "Customers", "Orders", "Products" },
ConflictResolution = ConflictResolutionStrategy.TimestampBased,
SyncInterval = TimeSpan.FromHours(6),
LastSyncTime = DateTime.Today,
EnableRealTimeSync = false
};
// Set up event handlers
syncManager.ProgressUpdated += (sender, args) =>
{
Console.WriteLine($"Progress: {args.CurrentEntity} - {args.ProcessedRecords} records processed");
monitor.LogSyncProgress(args.CurrentEntity, args.ProcessedRecords, args.TotalRecords ?? 0, TimeSpan.FromSeconds(60));
};
syncManager.SyncCompleted += (sender, args) =>
{
Console.WriteLine($"Sync completed: {args.Result.Success}");
monitor.LogSyncCompletion(args.Result);
};
syncManager.ErrorOccurred += (sender, args) =>
{
Console.WriteLine($"Sync error: {args.Exception.Message}");
};
try
{
// Execute synchronization
monitor.LogSyncStart(config);
var result = await syncManager.ExecuteSync(config);
// Display results
Console.WriteLine($"Sync Result:");
Console.WriteLine($" Success: {result.Success}");
Console.WriteLine($" Records Processed: {result.RecordsProcessed}");
Console.WriteLine($" Duration: {result.Duration.TotalMinutes:F1} minutes");
if (!result.Success)
{
Console.WriteLine($" Error: {result.ErrorMessage}");
}
// Generate health report
var healthReport = monitor.GenerateHealthReport();
Console.WriteLine($"Health Report:");
Console.WriteLine($" Average Throughput: {healthReport.AverageThroughput:F1} records/sec");
Console.WriteLine($" System Health: {healthReport.SystemHealth}");
}
catch (Exception ex)
{
Console.WriteLine($"Sync failed with exception: {ex.Message}");
}
}
private static IDMEEditor InitializeDMEEditor()
{
// Initialize using Autofac pattern from README
var builder = new ContainerBuilder();
// Register core services
builder.RegisterType<DMEEditor>().As<IDMEEditor>().SingleInstance();
builder.RegisterType<ConfigEditor>().As<IConfigEditor>().SingleInstance();
builder.RegisterType<DMLogger>().As<IDMLogger>().SingleInstance();
builder.RegisterType<Util>().As<IUtil>().SingleInstance();
builder.RegisterType<ErrorsInfo>().As<IErrorsInfo>().SingleInstance();
builder.RegisterType<JsonLoader>().As<IJsonLoader>().SingleInstance();
builder.RegisterType<AssemblyHandler>().As<IAssemblyHandler>().SingleInstance();
var container = builder.Build();
var dmeEditor = container.Resolve<IDMEEditor>();
// Add required configurations for IDataSource support
AddAllConnectionConfigurations(dmeEditor);
AddAllDataSourceMappings(dmeEditor);
AddAllDataSourceQueryConfigurations(dmeEditor);
return dmeEditor;
}
}
Best Practices
- Use full sync for initial data loads and complete refreshes
- Use incremental sync for regular updates with minimal data changes
- Use bidirectional sync carefully with robust conflict resolution
- Consider real-time sync only for critical, low-volume scenarios
- Monitor memory usage during large sync operations
- Use appropriate batch sizes based on data volume and complexity
- Implement connection pooling and resource management
- Consider network latency and bandwidth in sync timing
- Implement comprehensive monitoring and alerting
- Plan for disaster recovery and sync rollback scenarios
- Test sync operations thoroughly in non-production environments
- Document sync processes and troubleshooting procedures