12 KiB
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
{
"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 جدول):
{
"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
cd /home/masoud/Apps/project/FourSat/DataMigration/FourSat.DataMigration
nano appsettings.json
تغییرات لازم:
- ✅
SourceDatabase: Username و Password را وارد کنید - ✅
TargetDatabase: Username و Password را وارد کنید - ✅
TableMappings: اگر mapping جدید دارید اضافه کنید
2. Build پروژه
dotnet build
3. اجرای Migration
dotnet run
4. مشاهده Logs
# 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
استراتژی:
- اولین تلاش: بلافاصله
- تلاش 2: بعد از 5 ثانیه
- تلاش 3: بعد از 10 ثانیه (exponential backoff)
- تلاش 4: بعد از 20 ثانیه
- تلاش 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
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
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
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
public interface IMigrationService
{
Task RunAsync(CancellationToken cancellationToken);
}
Services/MigrationService.cs
public class MigrationService : IMigrationService
{
// کلاس اصلی که:
// 1. لیست table ها را از source میخواند
// 2. QueueManager را راهاندازی میکند
// 3. TableMigrator ها را همزمان اجرا میکند
// 4. Progress و statistics را نمایش میدهد
}
Program.cs
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<MigrationSettings>(context.Configuration.GetSection("MigrationSettings"));
services.AddSingleton<IMigrationService, MigrationService>();
// Register other services...
})
.Build();
await host.Services.GetRequiredService<IMigrationService>().RunAsync(CancellationToken.None);
توقف و ادامه (Pause/Resume)
نحوه توقف:
Ctrl+C # Graceful shutdown
نحوه ادامه:
- هیچ state ذخیره نمیشود (stateless)
- دوباره
dotnet runکنید - چون
INSERTاستفاده میشود، رکوردهای duplicate ایجاد میشود - پیشنهاد: قبل از اجرای مجدد، Target را TRUNCATE کنید
برای Production:
- از
MERGEیاINSERT IF NOT EXISTSاستفاده کنید - یک جدول
MigrationStateبرای ذخیره پیشرفت ایجاد کنید
نکات امنیتی
-
Credentials:
- ❌ هرگز appsettings.json را commit نکنید
- ✅ از Environment Variables یا User Secrets استفاده کنید
-
Network:
- ✅ از VPN برای اتصال به Production استفاده کنید
- ✅ IP شما در Firewall مجاز باشد
-
Permissions:
- Source: فقط
SELECTکافی است - Target: نیاز به
INSERTدارد
- Source: فقط
بهینهسازی عملکرد
برای دیتابیس کوچک (<100K records):
{
"BatchSize": 5000,
"MaxConcurrentTables": 5
}
برای دیتابیس متوسط (100K-1M):
{
"BatchSize": 2000,
"MaxConcurrentTables": 3
}
برای دیتابیس بزرگ (>1M):
{
"BatchSize": 500,
"MaxConcurrentTables": 2
}
حذف یا خاموش کردن
خاموش کردن موقت:
# فقط اجرا نکنید!
حذف کامل:
cd /home/masoud/Apps/project/FourSat
rm -rf DataMigration/
لایسنس
این ابزار موقت برای استفاده داخلی FourSat است. بعد از sync کامل، حذف شود.
سوالات متداول (FAQ)
Q: چرا بعضی table ها migrate نمیشوند؟ A: چک کنید:
- Table در Target وجود دارد؟
- Schema match میکند؟
- Mapping صحیح است؟
Q: چگونه فقط یک table خاص را migrate کنم؟
A: در کد MigrationService.cs، فیلتر اضافه کنید:
var tablesToMigrate = allTables.Where(t => t == "Users").ToList();
Q: چگونه از duplicate جلوگیری کنم؟ A: قبل از اجرا، Target را خالی کنید:
TRUNCATE TABLE [CMS].[Categories];
TRUNCATE TABLE [CMS].[Products];
-- ...
Q: آیا میتوانم بدون توقف سرور اجرا کنم؟
A: بله، فقط SELECT روی Source اجرا میشود (ReadOnly).
آخرین بروزرسانی: December 6, 2025
نسخه: 1.0
وضعیت: آماده برای پیادهسازی نهایی