Sdílet prostřednictvím


Jak přizpůsobit pořadí pracovních procesů pro nejlepší režim distribuce pracovních procesů

Režim best-worker distribuce vybere pracovní procesy, které jsou nejlépe schopny zpracovat první úlohu. Logiku řazení pracovních procesů je možné přizpůsobit pomocí výrazu nebo funkce Azure pro porovnání dvou pracovních procesů. Následující příklad ukazuje, jak přizpůsobit tuto logiku pomocí vlastní funkce Azure Functions.

Scénář: Vlastní pravidlo bodování v nejlepším režimu distribuce pracovního procesu

Chceme distribuovat nabídky mezi jejich pracovníky přidružené k frontě. Pracovníkům bude přiděleno skóre na základě jejich popisků a sady dovedností. Pracovní proces s nejvyšším skóre by měl získat první nabídku (režim distribuce BestWorker).

Diagram showing Best Worker Distribution Mode problem statement

Situace

  • Úloha byla vytvořena a klasifikována.
    • Úloha má přidružené následující popisky :
      • ["CommunicationType"] = "Chat"
      • ["IssueType"] = "XboxSupport"
      • ["Language"] = "en"
      • ["HighPriority"] = true
      • ["SubIssueType"] = "ConsoleMalfunction"
      • ["ConsoleType"] = "XBOX_SERIES_X"
      • ["Model"] = "XBOX_SERIES_X_1TB"
    • Úloha má přiřazené následující funkce WorkerSelectors
      • ["Angličtina"] >= 7
      • ["ChatSupport"] = true
      • ["XboxSupport"] = true
  • Úloha je momentálně ve stavu Zařazení do fronty. Fronta podpory hardwaru xboxu čeká na shodu s pracovním procesem.
  • Současně bude k dispozici více pracovních procesů.
    • Pracovní proces 1 byl vytvořen s následujícími popisky.
      • ["HighPrioritySupport"] = true
      • ["HardwareSupport"] = true
      • ["Support_XBOX_SERIES_X"] = true
      • ["Angličtina"] = 10
      • ["ChatSupport"] = true
      • ["XboxSupport"] = true
    • Pracovní proces 2 byl vytvořen s následujícími popisky.
      • ["HighPrioritySupport"] = true
      • ["HardwareSupport"] = true
      • ["Support_XBOX_SERIES_X"] = true
      • ["Support_XBOX_SERIES_S"] = true
      • ["Angličtina"] = 8
      • ["ChatSupport"] = true
      • ["XboxSupport"] = true
    • Pracovní proces 3 byl vytvořen s následujícími popisky.
      • ["HighPrioritySupport"] = false
      • ["HardwareSupport"] = true
      • ["Support_XBOX"] = true
      • ["Angličtina"] = 7
      • ["ChatSupport"] = true
      • ["XboxSupport"] = true

Očekávání

Při vyhodnocování pracovních procesů bychom chtěli následující chování vybrat, který pracovník získá první nabídku.

Decision flow diagram for scoring worker

Rozhodovací tok (jak je znázorněno výše) je následující:

  • Pokud úloha není vysokápriorita:

    • Pracovní procesy s popiskem: ["Support_XBOX"] = true; získá skóre 100
    • V opačném případě získejte skóre 1.
  • Pokud je úloha HighPriority:

    • Pracovní procesy s popiskem: ["HighPrioritySupport"] = false; získá skóre 1.
    • Jinak, pokud ["HighPrioritySupport"] = true:
      • Specializuje se pracovní proces na typ konzoly –> má pracovní proces popisek: ["Support_<jobLabels.ConsoleType>"] = true? Pokud je pravda, pracovní proces získá skóre 200
      • Jinak získáte skóre 100

Vytvoření funkce Azure

Než se pustíme do dalšího procesu, pojďme nejprve definovat funkci Azure, která ohodnocuje pracovní proces.

Poznámka:

Následující funkce Azure používá JavaScript. Další informace najdete v rychlém startu: Vytvoření funkce JavaScriptu v Azure pomocí editoru Visual Studio Code

Ukázkový vstup pro pracovní proces 1

{
  "job": {
    "CommunicationType": "Chat",
    "IssueType": "XboxSupport",
    "Language": "en",
    "HighPriority": true,
    "SubIssueType": "ConsoleMalfunction",
    "ConsoleType": "XBOX_SERIES_X",
    "Model": "XBOX_SERIES_X_1TB"
  },
  "selectors": [
    {
      "key": "English",
      "operator": "GreaterThanEqual",
      "value": 7,
      "expiresAfterSeconds": null
    },
    {
      "key": "ChatSupport",
      "operator": "Equal",
      "value": true,
      "expiresAfterSeconds": null
    },
    {
      "key": "XboxSupport",
      "operator": "Equal",
      "value": true,
      "expiresAfterSeconds": null
    }
  ],
  "worker": {
    "Id": "e3a3f2f9-3582-4bfe-9c5a-aa57831a0f88",
    "HighPrioritySupport": true,
    "HardwareSupport": true,
    "Support_XBOX_SERIES_X": true,
    "English": 10,
    "ChatSupport": true,
    "XboxSupport": true
  }
}

Ukázková implementace:

module.exports = async function (context, req) {
    context.log('Best Worker Distribution Mode using Azure Function');

    let score = 0;
    const jobLabels = req.body.job;
    const workerLabels = req.body.worker;

    const isHighPriority = !!jobLabels["HighPriority"];
    context.log('Job is high priority? Status: ' + isHighPriority);

    if(!isHighPriority) {
        const isGenericXboxSupportWorker = !!workerLabels["Support_XBOX"];
        context.log('Worker provides general xbox support? Status: ' + isGenericXboxSupportWorker);

        score = isGenericXboxSupportWorker ? 100 : 1;

    } else {
        const workerSupportsHighPriorityJob = !!workerLabels["HighPrioritySupport"];
        context.log('Worker provides high priority support? Status: ' + workerSupportsHighPriorityJob);

        if(!workerSupportsHighPriorityJob) {
            score = 1;
        } else {
            const key = `Support_${jobLabels["ConsoleType"]}`;
            
            const workerSpecializeInConsoleType = !!workerLabels[key];
            context.log(`Worker specializes in consoleType: ${jobLabels["ConsoleType"]} ? Status: ${workerSpecializeInConsoleType}`);

            score = workerSpecializeInConsoleType ? 200 : 100;
        }
    }
    context.log('Final score of worker: ' + score);

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: score
    };
}

Výstup pro pracovní proces 1

200

S výše uvedenou implementací získáme pro danou úlohu následující skóre pro pracovníky:

Pracovní podproces Skóre
Pracovní proces 1 200
Pracovní proces 2 200
Pracovní proces 3 0

Distribuce nabídek na základě nejlepšího pracovního režimu

Teď, když je aplikace funkcí Azure připravená, vytvoříme instanci režimu BestWorkerDistribution pomocí sady SDK směrovače.

var administrationClient = new JobRouterAdministrationClient("<YOUR_ACS_CONNECTION_STRING>");

// Setup Distribution Policy
var distributionPolicy = await administrationClient.CreateDistributionPolicyAsync(
    new CreateDistributionPolicyOptions(
        distributionPolicyId: "BestWorkerDistributionMode",
        offerExpiresAfter: TimeSpan.FromMinutes(5),
        mode: new BestWorkerMode(scoringRule: new FunctionRouterRule(new Uri("<insert function url>")))
    ) { Name = "XBox hardware support distribution" });

// Setup Queue
var queue = await administrationClient.CreateQueueAsync(
    new CreateQueueOptions(
        queueId: "XBox_Hardware_Support_Q",
        distributionPolicyId: distributionPolicy.Value.Id
    ) { Name = "XBox Hardware Support Queue" });

// Create workers
var worker1 = await client.CreateWorkerAsync(new CreateWorkerOptions(workerId: "Worker_1", capacity: 100)
    {
        Queues = { queue.Value.Id },
        Channels = { new RouterChannel(channelId: "Xbox_Chat_Channel", capacityCostPerJob: 10) },
        Labels =
        {
            ["English"] = new RouterValue(10),
            ["HighPrioritySupport"] = new RouterValue(true),
            ["HardwareSupport"] = new RouterValue(true),
            ["Support_XBOX_SERIES_X"] = new RouterValue(true),
            ["ChatSupport"] = new RouterValue(true),
            ["XboxSupport"] = new RouterValue(true)
        }
    });

var worker2 = await client.CreateWorkerAsync(new CreateWorkerOptions(workerId: "Worker_2", capacity: 100)
    {
        Queues = { queue.Value.Id },
        Channels = { new RouterChannel(channelId: "Xbox_Chat_Channel", capacityCostPerJob: 10) },
        Labels =
        {
            ["English"] = new RouterValue(8),
            ["HighPrioritySupport"] = new RouterValue(true),
            ["HardwareSupport"] = new RouterValue(true),
            ["Support_XBOX_SERIES_X"] = new RouterValue(true),
            ["ChatSupport"] = new RouterValue(true),
            ["XboxSupport"] = new RouterValue(true)
        }
    });

var worker3 = await client.CreateWorkerAsync(new CreateWorkerOptions(workerId: "Worker_3", capacity: 100)
    {
        Queues = { queue.Value.Id },
        Channels = { new RouterChannel(channelId: "Xbox_Chat_Channel", capacityCostPerJob: 10) },
        Labels =
        {
            ["English"] = new RouterValue(7),
            ["HighPrioritySupport"] = new RouterValue(true),
            ["HardwareSupport"] = new RouterValue(true),
            ["Support_XBOX_SERIES_X"] = new RouterValue(true),
            ["ChatSupport"] = new RouterValue(true),
            ["XboxSupport"] = new RouterValue(true)
        }
    });

// Create Job
var job = await client.CreateJobAsync(
    new CreateJobOptions(jobId: "job1", channelId: "Xbox_Chat_Channel", queueId: queue.Value.Id)
    {
        Priority = 100,
        ChannelReference = "ChatChannel",
        RequestedWorkerSelectors =
        {
            new RouterWorkerSelector(key: "English", labelOperator: LabelOperator.GreaterThanEqual, value: new RouterValue(7)),
            new RouterWorkerSelector(key: "ChatSupport", labelOperator: LabelOperator.Equal, value: new RouterValue(true)),
            new RouterWorkerSelector(key: "XboxSupport", labelOperator: LabelOperator.Equal, value: new RouterValue(true))
        },
        Labels =
        {
            ["CommunicationType"] = new RouterValue("Chat"),
            ["IssueType"] = new RouterValue("XboxSupport"),
            ["Language"] = new RouterValue("en"),
            ["HighPriority"] = new RouterValue(true),
            ["SubIssueType"] = new RouterValue("ConsoleMalfunction"),
            ["ConsoleType"] = new RouterValue("XBOX_SERIES_X"),
            ["Model"] = new RouterValue("XBOX_SERIES_X_1TB")
        }
    });

// Wait a few seconds and see which worker was matched
await Task.Delay(TimeSpan.FromSeconds(5));
var getJob = await client.GetJobAsync(job.Value.Id);
Console.WriteLine(getJob.Value.Assignments.Select(assignment => assignment.Value.WorkerId).First());

Výstup

Worker_1 // or Worker_2

Since both workers, Worker_1 and Worker_2, get the same score of 200,
the worker who has been idle the longest will get the first offer.