Classificar um trabalho

Aprenda a usar uma política de classificação no Job Router para resolver dinamicamente a fila e a prioridade e, ao mesmo tempo, anexar seletores de trabalhadores a um Trabalho.

Pré-requisitos

Criar uma política de classificação

O exemplo a seguir aproveita as expressões PowerFx para selecionar a fila e a prioridade. A expressão tenta corresponder ao rótulo Job chamado Region igual para NA resultar no Job sendo colocado no XBOX_NA_QUEUE. Caso contrário, o trabalho será enviado para a fila XBOX_DEFAULT_QUEUE de fallback, conforme definido pelo fallbackQueueId. Além disso, a prioridade é se um rótulo chamado Hardware_VIP foi correspondido, caso contrário, é .101

var classificationPolicy = await administrationClient.CreateClassificationPolicyAsync(
    new CreateClassificationPolicyOptions(classificationPolicyId: "XBOX_NA_QUEUE_Priority_1_10")
    {
        Name = "Select XBOX Queue and set priority to 1 or 10",
        QueueSelectorAttachments =
        {
            new ConditionalQueueSelectorAttachment(condition: new ExpressionRouterRule("job.Region = \"NA\""),
                queueSelectors: new List<RouterQueueSelector>
                {
                    new(key: "Id", labelOperator: LabelOperator.Equal, value: new RouterValue("XBOX_NA_QUEUE"))
                })
        },
        FallbackQueueId = "XBOX_DEFAULT_QUEUE",
        PrioritizationRule = new ExpressionRouterRule("If(job.Hardware_VIP = true, 10, 1)"),
    });
var classificationPolicy = await client.path("/routing/classificationPolicies/{classificationPolicyId}", 
        "XBOX_NA_QUEUE_Priority_1_10").patch({
    body: {
        name: "Select XBOX Queue and set priority to 1 or 10",
        queueSelectorAttachments: [{            
            kind: "conditional",
            condition: {
                kind: "expression",
                expression: 'job.Region = "NA"'
            },
            queueSelectors: [{
                key: "Id",
                labelOperator: "equal",
                value: "XBOX_NA_QUEUE"
            }]
        }],
        fallbackQueueId: "XBOX_DEFAULT_QUEUE",
        prioritizationRule: {
            kind: "expression",
            expression: "If(job.Hardware_VIP = true, 10, 1)"
        }
    },
    contentType: "application/merge-patch+json"
});
classification_policy: ClassificationPolicy = administration_client.upsert_classification_policy(
    classification_policy_id = "XBOX_NA_QUEUE_Priority_1_10",
    name = "Select XBOX Queue and set priority to 1 or 10",
    queue_selector_attachments = [
        ConditionalQueueSelectorAttachment(
            condition = ExpressionRouterRule(expression = 'job.Region = "NA"'),
            queue_selectors = [
                RouterQueueSelector(key = "Id", label_operator = LabelOperator.EQUAL, value = "XBOX_NA_QUEUE")
            ]
        )
    ],
    fallback_queue_id = "XBOX_DEFAULT_QUEUE",
    prioritization_rule = ExpressionRouterRule(expression = "If(job.Hardware_VIP = true, 10, 1)")))
ClassificationPolicy classificationPolicy = administrationClient.createClassificationPolicy(
    new CreateClassificationPolicyOptions("XBOX_NA_QUEUE_Priority_1_10")
        .setName("Select XBOX Queue and set priority to 1 or 10")
        .setQueueSelectors(List.of(new ConditionalQueueSelectorAttachment(
            new ExpressionRouterRule("job.Region = \"NA\""),
            List.of(new RouterQueueSelector("Id", LabelOperator.EQUAL, new RouterValue("XBOX_NA_QUEUE"))))))
        .setFallbackQueueId("XBOX_DEFAULT_QUEUE")
        .setPrioritizationRule(new ExpressionRouterRule().setExpression("If(job.Hardware_VIP = true, 10, 1)")));

Submeter o trabalho

O exemplo a seguir faz com que a política de classificação avalie os rótulos de trabalho. O resultado coloca o Trabalho na fila chamada XBOX_NA_QUEUE e define a prioridade como 1. Antes de a política de classificação ser avaliada, o estado do trabalho é pendingClassification. Uma vez que a política de classificação é avaliada, o estado do trabalho é atualizado para queued.

var job = await client.CreateJobWithClassificationPolicyAsync(new CreateJobWithClassificationPolicyOptions(
    jobId: "job1",
    channelId: "voice",
    classificationPolicyId: classificationPolicy.Value.Id)
{
    Labels =
    {
        ["Region"] = new RouterValue("NA"),
        ["Caller_Id"] = new RouterValue("7805551212"),
        ["Caller_NPA_NXX"] = new RouterValue("780555"),
        ["XBOX_Hardware"] = new RouterValue(7)
    }
});
var job = await client.path("/routing/jobs/{jobId}", "job1").patch({
    body: {
        channelId: "voice",
        classificationPolicyId: "XBOX_NA_QUEUE_Priority_1_10",
        labels: {
            Region: "NA",
            Caller_Id: "7805551212",
            Caller_NPA_NXX: "780555",
            XBOX_Hardware: 7
        }
    },
    contentType: "application/merge-patch+json"
});
job = client.upsert_job(
    job_id = "job1",
    channel_id = "voice",
    classification_policy_id = "XBOX_NA_QUEUE_Priority_1_10",
    labels = {
        "Region": "NA",
        "Caller_Id": "7805551212",
        "Caller_NPA_NXX": "780555",
        "XBOX_Hardware": 7
    }
)
RouterJob job = client.createJob(new CreateJobWithClassificationPolicyOptions("job1", "voice", "XBOX_NA_QUEUE_Priority_1_10")
    .setLabels(Map.of(
        "Region", new RouterValue("NA"),
        "Caller_Id": new RouterValue("7805551212"),
        "Caller_NPA_NXX": new RouterValue("780555"),
        "XBOX_Hardware": new RouterValue(7)
    )));

Anexando seletores de trabalhadores

Você pode usar a política de classificação para anexar mais seletores de trabalhadores a um trabalho.

Anexos estáticos

Neste exemplo, a Política de Classificação é configurada com um anexo estático, que sempre anexa o seletor de rótulo especificado a um trabalho.

await administrationClient.CreateClassificationPolicyAsync(
    new CreateClassificationPolicyOptions("policy-1")
    {
        WorkerSelectorAttachments =
        {
            new StaticWorkerSelectorAttachment(new RouterWorkerSelector(
                key: "Foo", labelOperator: LabelOperator.Equal, value: new RouterValue("Bar")))
        }
    });
await client.path("/routing/classificationPolicies/{classificationPolicyId}", "policy-1").patch({
    body: {
        workerSelectorAttachments: [{
            kind: "static",
            workerSelector: { key: "Foo", labelOperator: "equal", value: "Bar" }
        }]
    },
    contentType: "application/merge-patch+json"
});
administration_client.upsert_classification_policy(
    classification_policy_id = "policy-1",
    worker_selector_attachments = [
        StaticWorkerSelectorAttachment(
            worker_selector = RouterWorkerSelector(key = "Foo", label_operator = LabelOperator.EQUAL, value = "Bar")
        )
    ])
administrationClient.createClassificationPolicy(new CreateClassificationPolicyOptions("policy-1")
    .setWorkerSelectorAttachments(List.of(
        new StaticWorkerSelectorAttachment(new RouterWorkerSelector("Foo", LabelOperator.EQUAL, new RouterValue("Bar"))))));

Anexos condicionais

Neste exemplo, a Política de Classificação é configurada com um anexo condicional. Assim, ele avalia uma condição em relação aos rótulos de trabalho para determinar se os seletores de rótulos devem ser anexados ao trabalho.

await administrationClient.CreateClassificationPolicyAsync(
    new CreateClassificationPolicyOptions("policy-1")
    {
        WorkerSelectorAttachments =
        {
            new ConditionalRouterWorkerSelectorAttachment(
                condition: new ExpressionRouterRule("job.Urgent = true"),
                workerSelectors: new List<RouterWorkerSelector>
                {
                    new(key: "Foo", labelOperator: LabelOperator.Equal, value: new RouterValue("Bar"))
                })
        }
    });
await client.path("/routing/classificationPolicies/{classificationPolicyId}", "policy-1").patch({
    body: {
        workerSelectorAttachments: [{
            kind: "conditional",
            condition: { kind: "expression", expression: "job.Urgent = true" },
            workerSelectors: [{ key: "Foo", labelOperator: "equal", value: "Bar" }]
        }]
    },
    contentType: "application/merge-patch+json"
});
administration_client.upsert_classification_policy(
    classification_policy_id = "policy-1",
    worker_selector_attachments = [
        ConditionalWorkerSelectorAttachment(
            condition = ExpressionRouterRule(expression = "job.Urgent = true"),
            worker_selectors = [
                RouterWorkerSelector(key = "Foo", label_operator = LabelOperator.EQUAL, value = "Bar")
            ]
        )
    ])
administrationClient.createClassificationPolicy(new CreateClassificationPolicyOptions("policy-1")
    .setWorkerSelectorAttachments(List.of(new ConditionalRouterWorkerSelectorAttachment(
        new ExpressionRouterRule("job.Urgent = true"),
        List.of(new RouterWorkerSelector("Foo", LabelOperator.EQUAL, new RouterValue("Bar")))))));

Anexos de Passagem

Neste exemplo, a Política de Classificação é configurada para anexar um seletor de trabalhador ("Foo" = "<value comes from "Foo" label of the job>") ao trabalho.

await administrationClient.CreateClassificationPolicyAsync(
    new CreateClassificationPolicyOptions("policy-1")
    {
        WorkerSelectorAttachments =
        {
            new PassThroughWorkerSelectorAttachment(key: "Foo", labelOperator: LabelOperator.Equal)
        }
    });
await client.path("/routing/classificationPolicies/{classificationPolicyId}", "policy-1").patch({
    body: {
        workerSelectorAttachments: [{ kind: "passThrough", key: "Foo", labelOperator: "equal" }]
    },
    contentType: "application/merge-patch+json"
});
administration_client.upsert_classification_policy(
    classification_policy_id = "policy-1",
    worker_selector_attachments = [
        PassThroughWorkerSelectorAttachment(
            key = "Foo", label_operator = LabelOperator.EQUAL, value = "Bar")
    ])
administrationClient.createClassificationPolicy(new CreateClassificationPolicyOptions("policy-1")
    .setWorkerSelectorAttachments(List.of(new PassThroughWorkerSelectorAttachment("Foo", LabelOperator.EQUAL))));

Anexos de alocação ponderados

Neste exemplo, a Política de Classificação é configurada com um anexo de alocação ponderada. Esta política divide os trabalhos de acordo com as ponderações especificadas e atribui diferentes seletores em conformidade. Aqui, 30% dos postos de trabalho devem ir para trabalhadores com o rótulo definido para e 70% devem ir para trabalhadores com o rótulo Vendor definido para AB.Vendor

await administrationClient.CreateClassificationPolicyAsync(new CreateClassificationPolicyOptions("policy-1")
    {
        WorkerSelectorAttachments =
        {
            new WeightedAllocationWorkerSelectorAttachment(new List<WorkerWeightedAllocation>
            {
                new (weight: 0.3, workerSelectors: new List<RouterWorkerSelector>
                {
                    new (key: "Vendor", labelOperator: LabelOperator.Equal, value: new RouterValue("A"))
                }),
                new (weight: 0.7, workerSelectors: new List<RouterWorkerSelector>
                {
                    new (key: "Vendor", labelOperator: LabelOperator.Equal, value: new RouterValue("B"))
                })
            })
        }
    });
await client.path("/routing/classificationPolicies/{classificationPolicyId}", "policy-1").patch({
    body: {
        workerSelectorAttachments: [{
            kind: "weightedAllocation",
            allocations: [
            { 
                weight: 0.3,
                workerSelectors: [{ key: "Vendor", labelOperator: "equal", value: "A" }]
            },
            { 
                weight: 0.7,
                workerSelectors: [{ key: "Vendor", labelOperator: "equal", value: "B" }]
            }]
        }]
    },
    contentType: "application/merge-patch+json"
});
administration_client.upsert_classification_policy(
    classification_policy_id = "policy-1",
    worker_selector_attachments = [ 
        WeightedAllocationWorkerSelectorAttachment(allocations = [
            WorkerWeightedAllocation(weight = 0.3, worker_selectors = [
                RouterWorkerSelector(key = "Vendor", label_operator = LabelOperator.EQUAL, value = "A")
            ]),
            WorkerWeightedAllocation(weight = 0.7, worker_selectors = [
                RouterWorkerSelector(key = "Vendor", label_operator = LabelOperator.EQUAL, value = "B")
            ])
        ])
    ])
administrationClient.createClassificationPolicy(new CreateClassificationPolicyOptions("policy-1")
    .setWorkerSelectorAttachments(List.of(new WeightedAllocationWorkerSelectorAttachment(
        List.of(new WorkerWeightedAllocation(0.3, List.of(
            new RouterWorkerSelector("Vendor", LabelOperator.EQUAL, new RouterValue("A")),
            new RouterWorkerSelector("Vendor", LabelOperator.EQUAL, new RouterValue("B"))
        )))))));

Reclassificar um trabalho após o envio

Depois que o Job Router tiver recebido e classificado um Job usando uma política, você terá a opção de reclassificá-lo usando o SDK. O exemplo a seguir ilustra uma maneira de aumentar a prioridade do Job para 10, simplesmente especificando a ID do Trabalho, chamando o método e atualizando o classificationPolicyId e incluindo o UpdateJobAsyncHardware_VIP rótulo.

await client.UpdateJobAsync(new RouterJob("job1") {
    ClassificationPolicyId = classificationPolicy.Value.Id,
    Labels = { ["Hardware_VIP"] = new RouterValue(true) }});
var job = await client.path("/routing/jobs/{jobId}", "job1").patch({
    body: {
        classificationPolicyId: classificationPolicy.body.id,
        labels: { Hardware_VIP: true }
    },
    contentType: "application/merge-patch+json"
});
client.upsert_job(
    job_id = "job1",
    classification_policy_id = classification_policy.id,
    labels = { "Hardware_VIP": True }
)
client.updateJob(new RouterJob("job1")
    .setClassificationPolicyId(classificationPolicy.getId())
    .setLabels(Map.of("Hardware_VIP", new RouterValue(true))));

Nota

Se os rótulos de trabalho, queueId, channelId ou seletores de trabalhador forem atualizados, todas as ofertas existentes no trabalho serão revogadas e você receberá um evento RouterWorkerOfferRevoked para cada oferta do EventGrid. O trabalho é colocado novamente na fila e você recebe um evento RouterJobQueued . As ofertas de emprego também podem ser revogadas quando a capacidade total de um trabalhador é reduzida ou os canais são atualizados.