Files
docs/archive/collected-docs/DataMigration
masoodafar-web 5965b98728 update
2026-01-03 18:27:49 +03:30
..
2026-01-03 18:27:49 +03:30
2026-01-03 18:27:49 +03:30
2026-01-03 18:27:49 +03:30
2026-01-03 18:27:49 +03:30
2026-01-03 18:27:49 +03:30
2026-01-03 18:27:49 +03:30

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

استراتژی:

  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

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 برای ذخیره پیشرفت ایجاد کنید

نکات امنیتی

  1. Credentials:

    • هرگز appsettings.json را commit نکنید
    • از Environment Variables یا User Secrets استفاده کنید
  2. Network:

    • از VPN برای اتصال به Production استفاده کنید
    • IP شما در Firewall مجاز باشد
  3. Permissions:

    • Source: فقط SELECT کافی است
    • Target: نیاز به INSERT دارد

بهینه‌سازی عملکرد

برای دیتابیس کوچک (<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: چک کنید:

  1. Table در Target وجود دارد؟
  2. Schema match می‌کند؟
  3. 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
وضعیت: آماده برای پیاده‌سازی نهایی