This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Friday, 12 December 2025
अधिकांश अतुल्यकालिक व्यवस्थाओं को या तो बहुत ज्यादा याद है (लॉग, कतारों, कचरा आप कभी नहीं चाहते थे)... या वे कुछ भी याद नहीं करते हैं (आग और तारवाले काले छेद कि पल कुछ गलत हो जाता है).
यह लेख कुछ अलग प्रस्तुत करता है:
एक तरीका जहाँ हर बार अतुल्यकालिक ऑपरेशन छोटी हो जाता है ट्रैक योग्य, निरीक्षण योग्य, फिर से चालू करें (p), स्वयं को शुद्ध कर रहा है कार्य इकाई - और पूरे प्रणाली निजी रहता है, बाध्य, तेजी से, और अनुमान लगाना।
यह मेरे पहले लेख का साथी है, **LRUS - जब तेज़ क्षमता आपके तंत्र को बेहतर बनाती है**यही कारण है कि एक जाँच ने दिखाया कि स्मृति + पार करना एक जीवित व्यवस्था बन जाता है।
यह एक अन्य आधे का पता लगाता है: बाध्य किया, एनहेर्निक चलाने वाला@ info: whatsthis - किस तरह सक्रिय कार्य का एक छोटा सा सफर हो जाता है, एक घटना लॉग और एक रीप्ले इंजन, बिना किसी उपयोगकर्ता डाटा को रखे.
उदाहरण मेरे चिट्ठे के अनुवाद विजेट - एक छोटे से यूआई से आता है का अनुवाद करने के लिए चित्र-चना पर सामग्री का अनुवाद करने के लिए। यह मामूली लग रहा है।
यह है पार्ट 1 दो भाग श्रंखला के लिए:
अब यह विशेष रूप से अल्पतम पैकेज में है 20 से अधिक।.
एनईएस.ईटी विकासकर्ता तीन बुरी विकल्प से चुनने के लिए कर रहे हैं:
आप Task.Run() कुछ, आशा है कि यह समाप्त होता है, और जब यह आप कुछ भी नहीं मिलता है.
आप ब्लॉक ब्लॉक ब्लॉक ब्लॉक नहीं करना चाहिए. नीचे दिए गए विस्फोटों से मर जाते हैं. आपके उपयोक्ता तुम से नफरत करते हैं.
अब आपके पास है:
उपयोगी... लेकिन बाहरी. साथ ही: यह कुछ भी खेल नहीं सकता और अक्सर लीक डेटा आप कभी स्टोर करने के लिए इरादा नहीं किया था.
हम वास्तव में क्या चाहते हैं:
"सिर्फ काफी लंबे समय" की याद क्या प्रणाली कर रही है और कुछ और नहीं.
यहाँ एक वाक्य में विचार है:
किक ऑपरेशन तुरंत बंद कर देता है, यह एक कार्य - विशेष रूप से एक कार्यीय स्रोत के माध्यम से, इसे साफ़ कर देता है, और अंतिम कुछ कार्यों की एक छोटी - सी धारा को साफ़ रखता है ताकि आप उन्हें किसी उपयोगकर्ता की सामग्री का निरीक्षण कर सकते हैं या निकाल सकते हैं ।
यह बीच में बैठता है:
... उनमें से किसी के बिना।
flowchart TB
subgraph Client["Client Request"]
R[Start Translation]
end
subgraph API["API Layer"]
A[Create TaskId] --> B[Create TaskCompletionSource]
B --> C[Queue to Channel]
C --> D[Return TaskId Immediately]
end
subgraph Cache["Ephemeral Cache (Bounded)"]
E[Store TranslateTask]
F[Max 5 per user]
G[6hr absolute / 1hr sliding expiry]
end
subgraph Worker["Background Worker"]
H[Read from Channel]
H --> I[Execute Translation]
I --> J[Complete TCS]
end
R --> A
B --> E
E --> F --> G
C --> H
style Cache fill:none,stroke:#10b981,stroke-width:2px
style Worker fill:none,stroke:#6366f1,stroke-width:2px
कोर डाटा स्ट्रक्चर एक है TranslateTask - एक द्वारा वापस किया गया एक छोटा सा परमाणु इकाई Task<TaskCompletion>:
// From TranslateTask.cs
public class TranslateTask(
string taskId,
DateTime startTime,
string language,
Task<TaskCompletion>? task)
: TranslateResultTask(taskId, startTime, language)
{
public Task<TaskCompletion>? Task { get; init; } = task;
}
public record TaskCompletion(
string? TranslatedMarkdown,
string OriginalMarkdown,
string Language,
bool Complete,
DateTime? EndTime);
इसमें समाहित है:
Task<TaskCompletion>यही कारण है कि कुछ भी नहीं था, डिस्क में कुछ भी नहीं लिखा गया है. कोई भी नहीं है जो एक रोलिंग विंडो से परे है.
AWS के पास कदम फंक्शन्स है. AWECANECANEANEANE. आप के बीच में है. आप के 30 लाइन है कि एक बादल के बिल की आवश्यकता नहीं है.
जादू में होता है BackgroundTranslateServiceहम एक का उपयोग करने के बजाय, आग और तार के बजाय, हम एक का इस्तेमाल करते हैं कार्य - एक वादा के रूप में बना कि हमें जल्दी वापस आने देता है... ... जबकि काम पृष्ठभूमि में होता है.
// From BackgroundTranslateService.cs
private readonly Channel<(PageTranslationModel, TaskCompletionSource<TaskCompletion>)>
_translations = Channel.CreateUnbounded<(PageTranslationModel, TaskCompletionSource<TaskCompletion>)>();
private async Task<Task<TaskCompletion>> Translate(PageTranslationModel message)
{
// Create a TaskCompletionSource that will eventually hold the result
var tcs = new TaskCompletionSource<TaskCompletion>();
// Send the translation request along with the TCS to be processed
await _translations.Writer.WriteAsync((message, tcs));
// Return the Task immediately -caller can await it or check status later
return tcs.Task;
}
यदि आप उपयोग नहीं किया है TaskCompletionSource<T> पहले, इसके बारे में एक के रूप में सोचो वादा करता है कि आप दस्ती रूप से नियंत्रित करेंनियमित तौर पर नहीं Task जो कि जब समाप्त हो जाए तो समाप्त हो जाता है टीसीएस पूर्ण आप कॉल SetResult(), SetException(), या SetCanceled().
यह आपको देता है:
Task (और) बुलाने वाले की तरफयह "आग-से- भूलें" और "आग और ट्रैक" के बीच पुल है.
जब उपभोक्ता क्लिक करे "सही", तो सामनेवाले को एपीआई कॉल करना:
// From translations.js
fetch('/api/translate/start-translation', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Language: shortCode,
OriginalMarkdown: markdown
})
})
.then(response => response.json())
.then(taskId => {
// Got a taskId immediately -translation is running in background
console.log("Task ID:", taskId);
// Poll for updates via HTMX
htmx.ajax('get', "/editor/get-translations", {
target: '#translations',
swap: 'innerHTML'
});
});
NORD तुरंत कार्य ID के साथ लौटाता है:
// From TranslateAPI.cs
[HttpPost("start-translation")]
public async Task<Results<Ok<string>, BadRequest<string>>> StartTranslation(
[FromBody] MarkdownTranslationModel model)
{
if (!backgroundTranslateService.TranslationServiceUp)
return TypedResults.BadRequest("Translation service is down");
// Create a unique identifier for this translation task
var taskId = Guid.NewGuid().ToString("N");
var userId = Request.GetUserId(Response);
// Trigger translation -returns Task<TaskCompletion> immediately
var translationTask = await backgroundTranslateService.Translate(model);
// Wrap it in our trackable TranslateTask
var translateTask = new TranslateTask(taskId, DateTime.Now, model.Language, translationTask);
// Store in the ephemeral cache (bounded, self-cleaning)
translateCacheService.AddTask(userId, translateTask);
// Return the task ID to the client -they can poll for status
return TypedResults.Ok(taskId);
}
प्रतिक्रिया त्वरित है. वास्तविक अनुवाद पृष्ठभूमि में चलाता है. उपयोक्ता को पोल कर सकता है या सिर्फ यूआई अद्यतन देख सकता है.
वह खास समझ जो हमारी समझ से परे है एलआरयू लेख यहाँ भी लागू करें:
तंत्र के बारे में डिबग और कारण रखने के लिए बस पर्याप्त इतिहास रखें... और प्राकृतिक सड़न सब कुछ और.
// From TranslateCacheService.cs
public class TranslateCacheService(IMemoryCache memoryCache)
{
public void AddTask(string userId, TranslateTask task)
{
if (memoryCache.TryGetValue(userId, out CachedTasks? tasks))
{
var currentTasks = tasks?.Tasks ?? new List<TranslateTask>();
currentTasks = currentTasks.OrderByDescending(x => x.StartTime).ToList();
// Keep only the 5 most recent tasks -bounded window
if (currentTasks.Count >= 5)
{
var lastTask = currentTasks.Last();
currentTasks.Remove(lastTask);
}
currentTasks.Add(task);
currentTasks = currentTasks.OrderByDescending(x => x.StartTime).ToList();
tasks!.Tasks = currentTasks;
memoryCache.Set(userId, tasks, new MemoryCacheEntryOptions
{
AbsoluteExpiration = tasks.AbsoluteExpiration,
SlidingExpiration = TimeSpan.FromHours(1)
});
}
else
{
// First task for this user
var cachedTasks = new CachedTasks
{
Tasks = new List<TranslateTask> { task },
AbsoluteExpiration = DateTime.Now.AddHours(6)
};
memoryCache.Set(userId, cachedTasks, new MemoryCacheEntryOptions
{
AbsoluteExpiration = cachedTasks.AbsoluteExpiration,
SlidingExpiration = TimeSpan.FromHours(1)
});
}
}
public List<TranslateTask> GetTasks(string userId)
{
if (memoryCache.TryGetValue(userId, out CachedTasks? tasks))
return tasks?.Tasks ?? new List<TranslateTask>();
return new List<TranslateTask>();
}
private class CachedTasks
{
public List<TranslateTask> Tasks { get; set; } = new();
public DateTime AbsoluteExpiration { get; set; }
}
}
हर नया कार्य:
flowchart LR
subgraph Window["Per-User Task Window (Max 5)"]
T1[Oldest Task] --- T2[Older] --- T3[Recent] --- T4[Newer] --- T5[Newest]
end
New[New Task] -->|Enqueue| Window
T1 -->|Evicted| Gone[(Expired)]
style Window fill:none,stroke:#10b981,stroke-width:2px
style Gone fill:none,stroke:#ef4444,stroke-width:2px
कोई फिर से ख़तरा नहीं है. कैश में कोई PIII I (सिर्फ कार्य आईडी, समय- अवधि, और भाषा कोड) में नहीं है ।
पृष्ठभूमि सेवा एक के लिए लागू होती है स्थिर विश्वास एक चैनल रीडर व गुण के प्रयोग से लूप करें Task.WhenAny:
// From BackgroundTranslateService.cs
private async Task TranslateFilesAsync(CancellationToken cancellationToken)
{
var processingTasks = new List<Task>();
while (!cancellationToken.IsCancellationRequested)
{
// Fill up to IPCount concurrent tasks (e.g., 4 parallel translations)
while (processingTasks.Count < markdownTranslatorService.IPCount &&
!cancellationToken.IsCancellationRequested)
{
var item = await _translations.Reader.ReadAsync(cancellationToken);
var translateModel = item.Item1;
var tcs = item.Item2;
// Start the task and add it to the list
var task = TranslateTask(cancellationToken, translateModel, item, tcs);
processingTasks.Add(task);
}
// Wait for ANY of the tasks to complete
var completedTask = await Task.WhenAny(processingTasks);
processingTasks.Remove(completedTask);
// Handle exceptions if needed
try
{
await completedTask;
}
catch (Exception ex)
{
logger.LogError(ex, "Error translating markdown");
}
}
}
यह एक तरह है भाप इंजन पर राज्यपाल▪ तनाव कम करने से तनाव कम होता है ।
यह पैटर्न आपको देता है:
जब वास्तविक अनुवाद कार्य समाप्त होता है, हम टीसीएस पूरा करते हैं:
// From BackgroundTranslateService.cs
private async Task TranslateTask(
CancellationToken cancellationToken,
PageTranslationModel translateModel,
(PageTranslationModel, TaskCompletionSource<TaskCompletion>) item,
TaskCompletionSource<TaskCompletion> tcs)
{
try
{
await retryPolicy.ExecuteAsync(async () =>
{
// Do the actual translation work
var translatedMarkdown = await markdownTranslatorService.TranslateMarkdown(
translateModel.OriginalMarkdown,
translateModel.Language,
cancellationToken);
// SUCCESS: Complete the TCS with the result
tcs.SetResult(new TaskCompletion(
translatedMarkdown,
translateModel.OriginalMarkdown,
translateModel.Language,
true,
DateTime.Now));
});
}
catch (TranslateException e)
{
// FAILURE: Complete the TCS with an exception
tcs.SetException(new Exception($"Translation failed after 3 retries: {e.Message}"));
}
catch (Exception e)
{
// UNEXPECTED: Complete the TCS with the exception
tcs.SetException(e);
}
}
कॉलर का Task<TaskCompletion> - जो वे तुरंत मिल गया जब वे बुलाया Translate() - वे कर सकते हैं:
await यह अगर वे ब्लॉक करना चाहते हैंIsCompleted सर्वे करने के लिएIsFaulted देखना है कि क्या यह असफल हो गया हैResult जिस अंक में ये लेख भी हैंजब उपयोक्ता को कार्यों को प्रदर्शित किया जाता है, हम जीवित कार्य को दृश्य मॉडल में रखते हैं:
// From TranslateTask.cs
public TranslateResultTask(TranslateTask task, bool includeMarkdown = false)
{
TaskId = task.TaskId;
StartTime = task.StartTime;
Language = task.Language;
// Check for faulted state first -a faulted task is also "completed" in .NET terms
if (task.Task?.IsFaulted == true)
{
Failed = true;
Completed = false;
TotalMilliseconds = (int)(DateTime.Now - task.StartTime).TotalMilliseconds;
}
else if (task.Task?.IsCompletedSuccessfully == true)
{
Completed = true;
Failed = false;
var endTime = task.Task.Result.EndTime;
TotalMilliseconds = (int)((endTime - task.StartTime)!).Value.TotalMilliseconds;
EndTime = endTime;
}
else
{
// Still in progress
Completed = false;
Failed = false;
TotalMilliseconds = (int)(DateTime.Now - task.StartTime).TotalMilliseconds;
}
if (Completed && includeMarkdown)
{
var result = task.Task?.Result;
if (result == null) return;
OriginalMarkdown = result.OriginalMarkdown;
TranslatedMarkdown = result.TranslatedMarkdown;
}
}
.नेट't Task कुछ quky राज्य संयोजन है:
IsCompleted के लिए सही है दोनों सफल हो गया तथा गलती की हुई कार्यIsCompletedSuccessfully सफलता के लिए केवल सही हैIsFaulted इसका अर्थ है कि इसने एक अपवाद निकालाIsCanceled इसका अर्थ है कि यह रद्द किया गया थातो आपको जांच करनी चाहिए IsFaulted जाँच से पहले IsCompleted, या आप सफलता के रूप में असफलों का इलाज करेंगे.
HMMX के उपयोग से अद्यतन के लिए दृश्य सर्वे hx-trigger:
@* From _GetTranslations.cshtml *@
@{
var allCompleted = Model.All(x => x.Completed);
var trigger = allCompleted ? "none" : "every 5s";
}
<div class="translationpoller"
hx-get="/editor/get-translations"
hx-swap="outerHTML"
hx-trigger="@trigger">
<table class="table">
@foreach (var item in Model)
{
<tr>
<td>
@if (item.Completed)
{
<a href="#" x-on:click.prevent="viewTranslation('@item.TaskId')">View</a>
}
else if (item.Failed)
{
<text>Failed</text>
}
else
{
<text>Processing</text>
}
</td>
<td>
@if (item.Completed)
{
<i class='bx bx-check text-green'></i>
}
else if (item.Failed)
{
<i class='bx bx-x text-red'></i>
}
else
{
<img src="~/img/3-dots-bounce.svg" />
}
</td>
<td>@item.Language</td>
<td>@TimeSpan.FromMilliseconds(item.TotalMilliseconds).Humanize()</td>
</tr>
}
</table>
</div>
चतुर सा: hx-trigger="@trigger" स्थिति पर आधारित परिवर्तन:
"none")यह है खुद को ज़बरदस्त मार रहे हैं - यह देखने के लिए कुछ भी नहीं है जब स्वचालित बंद हो जाता है.
जब उपयोक्ता क्लिक करे "View - >", हम पूरा अनुवाद लाते हैं:
// From TranslateAPI.cs
[HttpGet("get-translation/{taskId}")]
public async Task<Results<JsonHttpResult<TranslateResultTask>, BadRequest<string>>> GetTranslation(
string taskId)
{
var userId = Request.GetUserId(Response);
var tasks = translateCacheService.GetTasks(userId);
var translationTask = tasks.FirstOrDefault(t => t.TaskId == taskId);
if (translationTask == null)
return TypedResults.BadRequest("Task not found");
// Include the markdown content in the response
var result = new TranslateResultTask(translationTask, includeMarkdown: true);
return TypedResults.Json(result);
}
जावास्क्रिप्ट तब संपादक देता है:
// From translations.js
export function viewTranslation(taskId) {
fetch(`/api/translate/get-translation/${taskId}`)
.then(response => response.json())
.then(data => {
// Show the translated content area
document.getElementById("translatedcontent").classList.remove("hidden");
// Populate the editors
var originalMde = window.mostlylucid.simplemde.getinstance('translatedcontentarea');
originalMde.value(data.originalMarkdown);
var mde = window.mostlylucid.simplemde.getinstance('markdowneditor');
mde.value(data.translatedMarkdown);
});
}
क्योंकि:
यह वस्तुओं की रचना है मैं चाहते हैं कि ब्राउज़र तथा फ्रन्टएण्ड फ्रेमवर्क का उपयोग सत्र संचालन के लिए किया गया था.
आप बहुत कठिन सोच के बिना क्या मिलता है:
एल. एल.) |---------|-----| | स्थिरता % 1 ने चैनल के माध्यम से जानकारी के आधार पर अनुमान लगाया: | ऋणात्मक फ़ीडबैक लूप ✔ याद रखने के लिए तनाव कम करने के साथ - साथ उसे कम - से - कम कुछ और लोड करने की कोशिश कीजिए । | डिबग गपशप निरीक्षण करने के लिए सही आपरेशन बस काफी लंबे समय के लिए मौजूद हैं | पुनःप्राप्त करने की क्षमता SpamAssassin सफलतापूर्वक समाप्त हो गया | शून्य डेटा फिर से गणना एक बार कामों के लिए गोपनीयता तथा सरल सुधार | चलाने के लिए स्वयं का चयन किया जा रहा है पुराना काम खत्म हो जाता है, BAR
वैसे ही LRU कैश ने व्यवहार की स्मृति को तेज़ किया है, जो दबा हुआ ऑपरेशन विंडो मृत्यु के दृष्टिकोण को तेज़ करता है ।
इसे प्रयोग करें जब:
इसे प्रयोग न करें:
यदि है एलआरयू लेख के बारे में था भूल जाने के द्वारा सीखना, यह एक के बारे में है प्रीपिंग द्वारा चलाया जा रहा है.
यह प्रणाली वास्तव में सहायक - और अधिक कुछ भी नहीं होने के लिए पर्याप्त याद करती है ।
यह है:
सबसे अच्छी बात है? आप पहले से ही यह कैसे लागू करें: एक TaskCompletionSource, एक Channel, एक IMemoryCache धीरे - धीरे बीतता जा रहा है और एक पृष्ठभूमि का काम करता है ।
आग ... और काफी भूल नहीं है.
में पार्ट 2: नयी लाइब्रेरी बनाना, हम इस पैटर्न को एक ड्रॉप इन सहायता में बदल देंगे:
EphemeralForEachAsync<T> - जैसे Parallel.ForEachAsync लेकिन ऑपरेशन के साथEphemeralWorkCoordinator<T> - एक लंबे समय से दिखाई दे रहे कार्य कतारAddEphemeralWorkCoordinator<TCoordinator> (की तरह AddHttpClient)© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.