# FourSat Data Migration Tool ## نگاه کلی این ابزار برای مهاجرت داده‌های دیتابیس از ساختار قدیمی (Production) به ساختار جدید (Stage) طراحی شده است. **ویژگی‌ها:** - ✅ Queue-based processing با retry logic - ✅ Error handling - آیتم‌های ناموفق به صف retry می‌روند - ✅ Logging کامل با Serilog (Console + File) - ✅ قابلیت توقف/ادامه (Pause/Resume) - ✅ Table name mapping (مثل Categorys → Categories) - ✅ Batch processing برای کارایی بهتر - ✅ Retry با Exponential Backoff - ✅ Progress tracking --- ## ساختار پروژه ``` FourSat.DataMigration/ ├── Program.cs # Entry point با Hosting ├── appsettings.json # تنظیمات (ConnectionStrings, Mappings) ├── Models/ │ ├── MigrationSettings.cs # تنظیمات migration │ ├── TableMapping.cs # نگاشت table ها │ └── MigrationQueueItem.cs # آیتم صف ├── Services/ │ ├── IMigrationService.cs # Interface │ ├── MigrationService.cs # سرویس اصلی migration │ ├── QueueManager.cs # مدیریت صف و retry │ └── TableMigrator.cs # مهاجرت یک table └── Logs/ # لاگ فایل‌ها (auto-created) ``` --- ## تنظیمات (`appsettings.json`) ### 1. ConnectionStrings ```json { "SourceDatabase": "Server=185.252.31.42,2019;Database=Foursat;...", "TargetDatabase": "Server=194.5.195.53,31433;Database=Foursat;..." } ``` **⚠️ توجه**: حتماً Username و Password را وارد کنید! ### 2. MigrationSettings - **BatchSize**: تعداد رکوردهای هر batch (پیشنهاد: 1000) - **MaxRetryAttempts**: حداکثر تلاش مجدد (5 بار) - **RetryDelaySeconds**: تأخیر بین retry ها (5 ثانیه) - **MaxConcurrentTables**: تعداد table های همزمان (3 عدد) - **EnableDetailedLogging**: لاگ جزئیات (true) - **SkipEmptyTables**: نادیده گرفتن table های خالی (true) ### 3. TableMappings نگاشت نام table قدیمی به جدید (33 جدول): ```json { "Categorys": "Categories", "ClubFeatures": "ClubFeatures", "ClubMembershipHistories": "ClubMembershipHistories", "ClubMemberships": "ClubMemberships", "CommissionPayoutHistories": "CommissionPayoutHistories", "Contracts": "Contracts", "FactorDetailss": "FactorDetails", "NetworkMembershipHistories": "NetworkMembershipHistories", "NetworkWeeklyBalances": "NetworkWeeklyBalances", "OtpTokens": "OtpTokens", "Packages": "Packages", "ProductGalleryss": "ProductGalleries", "ProductImagess": "ProductImages", "Productss": "Products", "PruductCategorys": "ProductCategories", "PruductTags": "ProductTags", "Roles": "Roles", "SystemConfigurationHistories": "SystemConfigurationHistories", "SystemConfigurations": "SystemConfigurations", "Tags": "Tags", "Transactionss": "Transactions", "UserAddresss": "UserAddresses", "UserCartss": "UserCarts", "UserClubFeatures": "UserClubFeatures", "UserCommissionPayouts": "UserCommissionPayouts", "UserContracts": "UserContracts", "UserOrders": "UserOrders", "UserRoles": "UserRoles", "Users": "Users", "UserWalletChangeLogs": "UserWalletChangeLogs", "UserWallets": "UserWallets", "WeeklyCommissionPools": "WeeklyCommissionPools", "WorkerExecutionLogs": "WorkerExecutionLogs" } ``` **چگونه کار می‌کند:** - اگر table در mapping باشد → از نام جدید استفاده می‌کند - اگر در mapping نباشد → همان نام را استفاده می‌کند - اگر table در target نباشد → Log می‌کند و skip می‌کند --- ## نحوه اجرا ### 1. ویرایش appsettings.json ```bash cd /home/masoud/Apps/project/FourSat/DataMigration/FourSat.DataMigration nano appsettings.json ``` **تغییرات لازم:** - ✅ `SourceDatabase`: Username و Password را وارد کنید - ✅ `TargetDatabase`: Username و Password را وارد کنید - ✅ `TableMappings`: اگر mapping جدید دارید اضافه کنید ### 2. Build پروژه ```bash dotnet build ``` ### 3. اجرای Migration ```bash dotnet run ``` ### 4. مشاهده Logs ```bash # Real-time console output # یا tail -f Logs/migration-20251206.txt ``` --- ## جریان کار (Workflow) ``` 1. خواندن تنظیمات از appsettings.json ↓ 2. اتصال به Source و Target databases ↓ 3. کشف تمام table های Source (CMS schema) ↓ 4. برای هر table: ├─ بررسی mapping (قدیمی → جدید) ├─ تعداد رکوردها را بخواند ├─ اگر خالی → skip (با log) ├─ اگر پر → افزودن به Queue └─ Log: "Table X → Y: N records" ↓ 5. پردازش Queue: ├─ تا MaxConcurrentTables همزمان ├─ هر table در batch ها (BatchSize) ├─ اگر error → Retry (MaxRetryAttempts) ├─ اگر بعد از retry fail → Log + Skip └─ پیشرفت را نمایش بده ↓ 6. گزارش نهایی: ├─ تعداد table های موفق ├─ تعداد table های ناموفق ├─ جمع رکوردهای migrate شده └─ مدت زمان کل ``` --- ## Retry Logic ### استراتژی: 1. **اولین تلاش**: بلافاصله 2. **تلاش 2**: بعد از 5 ثانیه 3. **تلاش 3**: بعد از 10 ثانیه (exponential backoff) 4. **تلاش 4**: بعد از 20 ثانیه 5. **تلاش 5**: بعد از 40 ثانیه **اگر همه fail شوند:** - Log error با جزئیات کامل - Table را از queue حذف کن - به table بعدی برو (متوقف نمی‌شود!) --- ## Error Handling ### خطاهای رایج: | خطا | دلیل | راه حل | |-----|------|--------| | **Login failed** | Username/Password اشتباه | appsettings.json را بررسی کنید | | **Table not found** | Table در target وجود ندارد | Migration بزنید یا از mapping صحیح استفاده کنید | | **Timeout** | Network کند یا batch زیاد | BatchSize را کاهش دهید | | **Deadlock** | همزمانی بالا | MaxConcurrentTables را کم کنید | | **Permission denied** | User دسترسی ندارد | سطح دسترسی SQL را بررسی کنید | --- ## مثال خروجی ``` [12:30:15 INF] Starting migration... [12:30:16 INF] Source: 30 tables found [12:30:16 INF] Mapping: Categorys → Categories [12:30:16 INF] Mapping: Productss → Products [12:30:17 INF] Queue: 28 tables added (2 empty skipped) [12:30:18 INF] Migrating: Categories (6 records) [12:30:18 INF] Success: Categories (6/6) - 100% [12:30:19 INF] Migrating: Products (150 records) [12:30:21 INF] Success: Products (150/150) - 100% ... [12:35:42 INF] === Migration Complete === [12:35:42 INF] Success: 28 tables, 45,320 records [12:35:42 INF] Failed: 0 tables [12:35:42 INF] Duration: 5 minutes 27 seconds ``` --- ## فایل‌های باقی مانده برای پیاده‌سازی ### Models/MigrationSettings.cs ```csharp public class MigrationSettings { public int BatchSize { get; set; } = 1000; public int MaxRetryAttempts { get; set; } = 5; public int RetryDelaySeconds { get; set; } = 5; public int MaxConcurrentTables { get; set; } = 3; public bool EnableDetailedLogging { get; set; } = true; public bool SkipEmptyTables { get; set; } = true; } ``` ### Models/TableMapping.cs ```csharp public class TableMapping { public string SourceTable { get; set; } = string.Empty; public string TargetTable { get; set; } = string.Empty; public long TotalRecords { get; set; } public long MigratedRecords { get; set; } public MigrationStatus Status { get; set; } } public enum MigrationStatus { Pending, InProgress, Completed, Failed, Retrying } ``` ### Models/MigrationQueueItem.cs ```csharp public class MigrationQueueItem { public string SourceTable { get; set; } = string.Empty; public string TargetTable { get; set; } = string.Empty; public long TotalRecords { get; set; } public int RetryCount { get; set; } public DateTime? LastAttempt { get; set; } public string? LastError { get; set; } } ``` ### Services/IMigrationService.cs ```csharp public interface IMigrationService { Task RunAsync(CancellationToken cancellationToken); } ``` ### Services/MigrationService.cs ```csharp public class MigrationService : IMigrationService { // کلاس اصلی که: // 1. لیست table ها را از source می‌خواند // 2. QueueManager را راه‌اندازی می‌کند // 3. TableMigrator ها را همزمان اجرا می‌کند // 4. Progress و statistics را نمایش می‌دهد } ``` ### Program.cs ```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; var host = Host.CreateDefaultBuilder(args) .UseSerilog((context, config) => config.ReadFrom.Configuration(context.Configuration)) .ConfigureServices((context, services) => { services.Configure(context.Configuration.GetSection("MigrationSettings")); services.AddSingleton(); // Register other services... }) .Build(); await host.Services.GetRequiredService().RunAsync(CancellationToken.None); ``` --- ## توقف و ادامه (Pause/Resume) **نحوه توقف:** ```bash Ctrl+C # Graceful shutdown ``` **نحوه ادامه:** - هیچ state ذخیره نمی‌شود (stateless) - دوباره `dotnet run` کنید - چون `INSERT` استفاده می‌شود، رکوردهای duplicate ایجاد می‌شود - **پیشنهاد**: قبل از اجرای مجدد، Target را TRUNCATE کنید **برای Production:** - از `MERGE` یا `INSERT IF NOT EXISTS` استفاده کنید - یک جدول `MigrationState` برای ذخیره پیشرفت ایجاد کنید --- ## نکات امنیتی 1. **Credentials**: - ❌ هرگز appsettings.json را commit نکنید - ✅ از Environment Variables یا User Secrets استفاده کنید 2. **Network**: - ✅ از VPN برای اتصال به Production استفاده کنید - ✅ IP شما در Firewall مجاز باشد 3. **Permissions**: - Source: فقط `SELECT` کافی است - Target: نیاز به `INSERT` دارد --- ## بهینه‌سازی عملکرد ### برای دیتابیس کوچک (<100K records): ```json { "BatchSize": 5000, "MaxConcurrentTables": 5 } ``` ### برای دیتابیس متوسط (100K-1M): ```json { "BatchSize": 2000, "MaxConcurrentTables": 3 } ``` ### برای دیتابیس بزرگ (>1M): ```json { "BatchSize": 500, "MaxConcurrentTables": 2 } ``` --- ## حذف یا خاموش کردن ### خاموش کردن موقت: ```bash # فقط اجرا نکنید! ``` ### حذف کامل: ```bash cd /home/masoud/Apps/project/FourSat rm -rf DataMigration/ ``` --- ## لایسنس این ابزار موقت برای استفاده داخلی FourSat است. بعد از sync کامل، حذف شود. --- ## سوالات متداول (FAQ) **Q: چرا بعضی table ها migrate نمی‌شوند؟** A: چک کنید: 1. Table در Target وجود دارد؟ 2. Schema match می‌کند؟ 3. Mapping صحیح است؟ **Q: چگونه فقط یک table خاص را migrate کنم؟** A: در کد `MigrationService.cs`، فیلتر اضافه کنید: ```csharp var tablesToMigrate = allTables.Where(t => t == "Users").ToList(); ``` **Q: چگونه از duplicate جلوگیری کنم؟** A: قبل از اجرا، Target را خالی کنید: ```sql TRUNCATE TABLE [CMS].[Categories]; TRUNCATE TABLE [CMS].[Products]; -- ... ``` **Q: آیا می‌توانم بدون توقف سرور اجرا کنم؟** A: بله، فقط `SELECT` روی Source اجرا می‌شود (ReadOnly). --- **آخرین بروزرسانی**: December 6, 2025 **نسخه**: 1.0 **وضعیت**: آماده برای پیاده‌سازی نهایی