- BackOffice/docs → totalDoc/backoffice/ (AUDIT + CHANGELOG) - FrontOffice/docs → totalDoc/frontoffice/ (CHANGELOG + UI-UNIFICATION-PLAN) - CMS/README.md → totalDoc/cms/CMS-README.md - DataMigration/README.md → totalDoc/migration/DATAMIGRATION-README.md - deployment/README.md → totalDoc/deployment/DEPLOYMENT-README.md - Updated INDEX.md with new paths and sections
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
وضعیت: آماده برای پیادهسازی نهایی