Blog

Integrating an External VOD Solution Without Touching the .NET Legacy

Sharing the process of integrating the Shoplive VOD solution into a legacy .NET ad system—which wasn't designed for video ads—launching a new ad product worth billions of KRW without impacting legacy stability.

Node.js.NETWebhookGmarketLegacy

Note: The code in this article has been conceptually rewritten based on actual work experience. It is not associated with the actual company code.

Integration Flow

AdvertiserUpload Video Creative .NET Ad Admin Shoplive APICreate Video Content ShopliveEncoding Process Encoding CompleteWebhook Creative Status: READYReady for Ad Serving

Introduction

Adding new features to a legacy system is always nerve-wracking. This is especially true for a production .NET system where thousands of ad products are being served in real-time.

This post shares the experience of adding a Video on Demand (VOD) ad product with minimal impact to a legacy ad admin system that was originally designed solely for image ads. Ultimately, this integration successfully launched a new video ad product on Gmarket and contributed to new revenue worth at least billions of KRW.


Problem Definition: What Was Difficult?

Limitations of the Legacy System

The existing .NET ad admin system was designed entirely around image banner ads. Everything from the data model to the UI was built based on image creatives.

Video ads are fundamentally different:

  • File Size: Images are a few hundred KBs; videos are tens to hundreds of MBs.
  • Processing: Images can be used immediately, but videos require encoding/transcoding.
  • Metadata: Videos have properties like playback time, resolution, and codec information that images don't have.
  • Status Management: The external system needs to confirm whether video processing has completed or failed.

Why Didn't We Completely Replace the Legacy System?

The simplest solution would have been to build a separate new video ad system, but this was practically impossible. Rebuilding dozens of well-functioning features—such as advertiser management, product registration, and the review process—would require far too much effort.

The conclusion was to modify the legacy system as minimally as possible and integrate it with an external VOD solution (Shoplive).


Design: Webhook-based One-way Synchronization

The core design decision was webhook-based one-way synchronization.

[Advertiser] → [.NET Admin] → [Shoplive API] → [Video Upload/Encoding]
                                    ↓
                            [Encoding Complete Webhook]
                                    ↓
                          [.NET Admin Status Update]

Instead of having the legacy .NET system periodically poll Shoplive for status updates, we chose a method where Shoplive notifies us via a webhook once processing is complete. The advantages of this approach are:

  1. Minimized load on the legacy system: Event-driven operation without polling.
  2. Near real-time status synchronization: Reflected immediately upon encoding completion.
  3. Minimized coupling: The legacy system does not depend on the external system's state.

Implementation Process

1. Minimal Modifications to the .NET Admin

We applied the absolute minimum changes to the legacy .NET system:

  • Added VIDEO to the Creative Type field.
  • Added video file upload processing logic.
  • Added Shoplive API call modules (content creation, info synchronization).
  • Added video processing status fields (PENDING / PROCESSING / READY / FAILED).
// Creative Type extension added to .NET Legacy
public enum CreativeType 
{
    IMAGE = 1,
    VIDEO = 2  // Newly added
}

// Shoplive Integration Service added
public class ShopliveService 
{
    public async Task<string> CreateContent(VideoCreativeDto dto)
    {
        var response = await _httpClient.PostAsync(
            "/api/v1/contents",
            JsonContent.Create(dto)
        );
        // Return external Content ID
        return (await response.Content.ReadFromJsonAsync<ShopliveResponse>()).ContentId;
    }
}

2. Stabilizing Integration: Handling Failures is Key

The most important aspect of external API integration is failure handling. Integrations can fail for various reasons: network errors, temporary Shoplive server outages, timeouts, etc.

public async Task SyncVideoStatus(string creativeId, string shopliveContentId)
{
    const int maxRetries = 3;
    for (int attempt = 0; attempt < maxRetries; attempt++)
    {
        try
        {
            var status = await _shopliveService.GetContentStatus(shopliveContentId);
            await UpdateCreativeStatus(creativeId, status);
            return;
        }
        catch (HttpRequestException ex) when (attempt < maxRetries - 1)
        {
            _logger.LogWarning("Shoplive integration failed, retry {attempt}: {message}", 
                attempt + 1, ex.Message);
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt))); // Exponential backoff
        }
    }
    // Alert on final failure
    await _alertService.SendAlert($"Final failure in Shoplive sync: {creativeId}");
}

3. Real-time Status Reflection on Ad Detail Lookup

When an advertiser views a registered video ad, the status in the DB and the actual processing status in Shoplive might differ. To prevent this, we checked the actual status in Shoplive during detailed lookups and updated the internal status to the latest.

public async Task<CreativeDetailDto> GetCreativeDetail(string creativeId)
{
    var creative = await _repository.GetById(creativeId);
    
    if (creative.Type == CreativeType.VIDEO && 
        creative.Status != VideoStatus.READY)
    {
        // Real-time status check and update
        var latestStatus = await _shopliveService.GetContentStatus(creative.ShopliveContentId);
        if (latestStatus != creative.Status)
        {
            await UpdateCreativeStatus(creativeId, latestStatus);
            creative.Status = latestStatus;
        }
    }
    
    return creative.ToDetailDto();
}

Results

While maintaining the stability of the legacy system:

  • Successfully launched the new video ad product.
  • Contributed to new ad revenue worth at least billions of KRW post-launch.
  • Maintained a 0% failure rate in the external VOD solution integration process (thanks to the retry logic).

Conclusion

A legacy system is not "something scary to touch," but rather "something where you must accurately identify the scope of impact and intervene minimally."

The biggest lesson learned in this project was the importance of strictly defining the scope of impact. By clearly defining the boundary of what to modify and what to build newly—and strictly adhering to that boundary—we were able to add new features without compromising legacy stability.