Como adicionar eventos faturáveis a um pacote de aplicativo

Quando você usa o Custom Event Billing para um Snowflake Native App, pode cobrar por tipos específicos de uso do aplicativo, além dos planos de preços baseados em uso existentes. Para configurá-lo, você deve executar duas etapas de alto nível:

  1. Configure seu pacote de aplicativo para emitir eventos faturáveis seguindo as etapas deste tópico.

  2. Selecione um plano de preços baseado em uso com eventos faturáveis para a listagem que você usa para publicar seu Snowflake Native App para os consumidores.

Este tópico descreve como configurar seu pacote de aplicativo para emitir eventos faturáveis usando a função do sistema SYSTEM$CREATE_BILLING_EVENT.

Visão geral da adição de eventos faturáveis a um pacote de aplicativo

Você pode configurar seu pacote de aplicativo para emitir eventos faturáveis em resposta a eventos de uso específicos para que possa cobrar dos consumidores com base no quanto eles usam seu Snowflake Native App.

Por exemplo, você pode adicionar um evento faturável para cobrar de um consumidor um valor específico para cada chamada de um procedimento armazenado em seu Snowflake Native App.

Para adicionar eventos faturáveis a um pacote de aplicativo, faça o seguinte:

  1. Crie procedimentos armazenados para definir quais eventos de uso acionam chamadas para a função do sistema SYSTEM$CREATE_BILLING_EVENT.

    Nota

    Você não pode testar a saída da função do sistema neste estágio. Esta função do sistema só pode ser chamada a partir de um Snowflake Native App instalado em uma conta de consumidor.

  2. Adicione esses procedimentos armazenados ao script de configuração do pacote de aplicativo.

Importante

O Snowflake oferece suporte a eventos faturáveis que são emitidos chamando a função do sistema em um procedimento armazenado no aplicativo, conforme descrito pelos exemplos neste tópico.

O Snowflake não oferece suporte a outros métodos de cálculo da cobrança básica para eventos faturáveis, como métodos que usam a saída de uma tabela ou função definida pelo usuário que gera atividade do consumidor ou métodos que usam telemetria registrada em uma tabela de eventos.

Se você não tiver certeza se uma implementação proposta terá suporte, entre em contato com seu representante da conta Snowflake.

Exemplos de eventos faturáveis

Os exemplos nesta seção mostram como criar procedimentos armazenados para emitir eventos faturáveis para cenários de cobrança comuns. Cada um desses exemplos chama a função createBillingEvent definida em Chamada da função SYSTEM$CREATE_BILLING_EVENT.

Chamada da função SYSTEM$CREATE_BILLING_EVENT

O exemplo a seguir mostra como criar uma função wrapper em um procedimento armazenado para chamar a função do sistema SYSTEM$CREATE_BILLING_EVENT.

Nota

Você pode chamar essa função do sistema em um procedimento armazenado escrito em JavaScript, Python ou Java.

Este exemplo cria um procedimento armazenado JavaScript chamado custom_event_billing no banco de dados db_1 e esquema public. O procedimento armazenado cria uma função auxiliar chamada createBillingEvent que recebe argumentos que correspondem aos parâmetros digitados esperados pela função do sistema SYSTEM$CREATE_BILLING_EVENT.

Para obter mais detalhes sobre os parâmetros e os tipos necessários, consulte SYSTEM$CREATE_BILLING_EVENT.

 CREATE OR REPLACE PROCEDURE db_1.public.custom_event_billing()
 RETURNS NULL
 LANGUAGE JAVASCRIPT
 AS
 $$
   /**
    * Helper method to add a billable event
    * Format timestamps as Unix timestamps in milliseconds
    */

   function createBillingEvent(className, subclassName, startTimestampVal, timestampVal, baseCharge, objects, additionalInfo) {
        try {
            var res = snowflake.createStatement({
            sqlText: `SELECT SYSTEM$CREATE_BILLING_EVENT('${className}',
                                                      '${subclassName}',
                                                      ${startTimestampVal},
                                                      ${timestampVal},
                                                      ${baseCharge},
                                                      '${objects}',
                                                      '${additionalInfo}')`
            }).execute();

            res.next();

            return res.getColumnValue(1);
        } catch(err) {
            return err.message;
        }
    }
$$;
Copy

Os exemplos neste tópico chamam essa função auxiliar.

Exemplo: cobrança baseada em chamadas para um procedimento armazenado

O exemplo a seguir mostra como criar um procedimento armazenado para emitir um evento faturável quando um consumidor chama esse procedimento armazenado em um Snowflake Native App.

Adicione este código de exemplo ao seu script de configuração no mesmo procedimento armazenado que define a função auxiliar:

...
  //
  // Send a billable event when a stored procedure is called.
  //
  var event_ts = Date.now();
  var billing_quantity = 1.0;
  var base_charge = billing_quantity;
  var objects = "[ \"db_1.public.procedure_1\" ]";
  var retVal = createBillingEvent("PROCEDURE_CALL", "", event_ts, event_ts, base_charge, objects, "");
  // Run the rest of the procedure ...
$$;
Copy

Este código de exemplo cria um procedimento armazenado que chama a função createBillingEvent para emitir um evento faturável com o nome da classe PROCEDURE_CALL e uma cobrança básica de 1.0.

Nota

Os tipos de argumentos passados para a função createBillingEvent deve corresponder aos parâmetros digitados esperados pela função do sistema SYSTEM$CREATE_BILLING_EVENT.

Exemplo: Faturamento com base em linhas consumidas por um Snowflake Native App

O exemplo a seguir mostra como criar um procedimento armazenado para emitir um evento faturável com base no número de linhas consumidas em uma tabela na conta do consumidor.

Adicione este código de exemplo ao seu script de configuração no mesmo procedimento armazenado que define a função auxiliar:

...
  // Run a query and get the number of rows in the result
  var select_query = "select i from db_1.public.t1";
  res = snowflake.execute ({sqlText: select_query});
  res.next();
  //
  // Send a billable event for rows returned from the select query
  //
  var event_ts = Date.now();
  var billing_quantity = 2.5;
  var base_charge = res.getRowcount() * billing_quantity;
  var objects = "[ \"db_1.public.t1\" ]";
  createBillingEvent("ROWS_CONSUMED", "", event_ts, event_ts, base_charge, objects, "");
  // Run the rest of the procedure ...
$$;
Copy

Este código de exemplo cria um procedimento armazenado que chama o createBillingEvent função para emitir um evento faturável com o nome da classe ROWS_CONSUMED e uma cobrança base calculada de 2.5 multiplicado pelo número de linhas no db_1.public.t1 tabela na conta do consumidor.

Nota

Os tipos de argumentos passados para a função createBillingEvent deve corresponder aos parâmetros digitados esperados pela função do sistema SYSTEM$CREATE_BILLING_EVENT.

Exemplo: cobrança com base no número de linhas ingeridas

O exemplo a seguir mostra como criar um procedimento armazenado para emitir um evento faturável com base no número de linhas ingeridas em uma tabela.

Adicione este código de exemplo ao seu script de configuração no mesmo procedimento armazenado que define a função auxiliar:

...
    // Run the merge query
    var merge_query = "MERGE INTO target_table USING source_table ON target_table.i = source_table.i
        WHEN MATCHED THEN UPDATE SET target_table.j = source_table.j
        WHEN NOT MATCHED
        THEN INSERT (i, j)
        VALUES (source_table.i, source_table.j)";
    res = snowflake.execute ({sqlText: merge_query});
    res.next();
    // rows ingested = rows inserted + rows updated
    var numRowsIngested = res.getColumnValue(1) + res.getColumnValue(2);

    //
    // Send a billable event for rows changed by the merge query
    //
    var event_ts = Date.now();
    var billing_quantity = 2.5;
    var base_charge = numRowsIngested * billing_quantity;
    var objects = "[ \"db_1.public.target_table\" ]";
    createBillingEvent("ROWS_CHANGED", "", event_ts, event_ts, base_charge, objects, "");
    // Run the rest of the procedure ...
$$;
Copy

Este código de exemplo cria um procedimento armazenado que chama a função createBillingEvent para emitir um evento faturável com o nome da classe ROWS_CHANGED e uma cobrança base calculada de 2.5 multiplicado pelo número de linhas ingeridas na tabela db_1.target_table.

Nota

Os tipos de argumentos passados para a função createBillingEvent deve corresponder aos parâmetros digitados esperados pela função do sistema SYSTEM$CREATE_BILLING_EVENT.

Faturamento baseado em linhas ativas mensais

As linhas ativas mensais são o número de linhas inseridas ou atualizadas pela primeira vez em um mês de calendário. Alguns provedores usam essa métrica para cobrar apenas dos consumidores por linhas exclusivas atualizadas em um mês. Você pode modificar este exemplo para contar usuários exclusivos ou identificar um local de carregamento de dados exclusivo para determinar uma cobrança básica.

O exemplo a seguir mostra como criar um procedimento armazenado para emitir um evento faturável com base no número de linhas ativas mensais. Adicione este código de exemplo ao seu script de configuração no mesmo procedimento armazenado que define a função auxiliar:

...
    //
    // Get monthly active rows
    //
    var monthly_active_rows_query = "
     SELECT
         count(*)
     FROM
         source_table
     WHERE
         source_table.i not in
         (
           SELECT
             i
           FROM
             target_table
           WHERE
             updated_on >= DATE_TRUNC('MONTH', CURRENT_TIMESTAMP)
         )";
    res = snowflake.execute ({sqlText: monthly_active_rows_query});
    res.next();
    var monthlyActiveRows = parseInt(res.getColumnValue(1));
    //
    // Run the merge query and update the updated_on values for the rows
    //
    var merge_query = "
        MERGE INTO
            target_table
        USING
            source_table
        ON
            target_table.i = source_table.i
        WHEN MATCHED THEN
         UPDATE SET target_table.j = source_table.j
                    ,target_table.updated_on = current_timestamp
        WHEN NOT MATCHED THEN
            INSERT (i, j, updated_on) VALUES (source_table.i, source_table.j, current_timestamp)";
    res = snowflake.execute ({sqlText: merge_query});
    res.next();
    //
    // Emit a billable event for monthly active rows changed by the merge query
    //
    var event_ts = Date.now();
    var billing_quantity = 0.02
    var base_charge = monthlyActiveRows * billing_quantity;
    var objects = "[ \"db_1.public.target_table\" ]";
    createBillingEvent("MONTHLY_ACTIVE_ROWS", "", event_ts, event_ts, base_charge, objects, "");
    // Run the rest of the procedure ...
$$;
Copy

Este código de exemplo cria um procedimento armazenado que determina o número de linhas ativas mensais usando uma consulta de mesclagem para identificar linhas exclusivas. O exemplo então calcula a cobrança base usando o valor da variável monthlyActiveRows e o billing_quantity. A cobrança básica é então passada para a função createBillingEvent.

Nota

Os tipos de argumentos passados para a função createBillingEvent deve corresponder aos parâmetros digitados esperados pela função do sistema SYSTEM$CREATE_BILLING_EVENT.

Em seu script de configuração, adicione este procedimento armazenado após o procedimento armazenado que chama a função do sistema SYSTEM$CREATE_BILLING_EVENT.

Exemplo do Snowpark Python: cobrança baseada em linhas consumidas

Se você deseja escrever seu procedimento armazenado no Snowpark Python para faturar com base nas linhas consumidas pelo seu Snowflake Native App, use o seguinte exemplo:

CREATE OR REPLACE PROCEDURE app_schema.billing_event_rows()
   RETURNS STRING
   LANGUAGE PYTHON
   RUNTIME_VERSION = '3.9'
   PACKAGES = ('snowflake-snowpark-python')
   HANDLER = 'run'
   EXECUTE AS OWNER
   AS $$
import time

# Helper method that calls the system function for billing
def createBillingEvent(session, class_name, subclass_name, start_timestamp, timestamp, base_charge, objects, additional_info):
   session.sql(f"SELECT SYSTEM$CREATE_BILLING_EVENT('{class_name}', '{subclass_name}', {start_timestamp}, {timestamp}, {base_charge}, '{objects}', '{additional_info}')").collect()
   return "Success"

# Handler function for the stored procedure
def run(session):
   # insert code to identify monthly active rows and calculate a charge
   try:

      # Run a query to select rows from a table
      query =  "select i from db_1.public.t1"
      res = session.sql(query).collect()

      # Define the price to charge per row
      billing_quantity = 2.5

      # Calculate the base charge based on number of rows in the result
      charge = len(res) * billing_quantity

      # Current time in Unix timestamp (epoch) time in milliseconds
      current_time_epoch = int(time.time() * 1000)

      return createBillingEvent(session, 'ROWS_CONSUMED', '', current_time_epoch, current_time_epoch, charge, '["billing_event_rows"]', '')
   except Exception as ex:
      return "Error " + ex
$$;
Copy

Este código de exemplo cria um procedimento armazenado que define um método auxiliar que chama o SYSTEM$CREATE_BILLING_EVENT função do sistema, bem como um método que chama esse método auxiliar, createBillingEvent, para emitir um evento faturável com o nome da classe ROWS_CONSUMED e uma taxa básica calculada multiplicando um preço de 2.5 US dólares pelo número de linhas no db_1.public.t1 tabela na conta do consumidor.

Nota

Os tipos de argumentos passados para a função createBillingEvent deve corresponder aos parâmetros digitados esperados pela função do sistema SYSTEM$CREATE_BILLING_EVENT.

Como testar o Custom Event Billing

Para certificar-se de que você configurou o Custom Event Billing corretamente e de que os eventos faturáveis sejam emitidos para eventos de uso conforme o esperado, faça o seguinte:

  1. Atualize seu pacote de aplicativo:

    1. Atualize seu script de configuração para incluir os procedimentos armazenados que emitam eventos faturáveis.

    2. Atualize seu pacote de aplicativo com o novo script de configuração.

    3. Atualize a versão e a diretriz de versão para seu pacote de aplicativo.

  2. Compartilhe o pacote de aplicativo com uma conta de consumidor em sua organização à qual você tenha acesso para:

    1. Criar uma listagem privada.

    2. Adicionar Custom Event Billing como o plano de preços para a listagem.

    3. Compartilhe com a conta do consumidor.

    4. Entre na conta do consumidor usando Snowsight.

    5. Instale o Snowflake Native App.

  3. Confirme se os procedimentos armazenados emitem com sucesso eventos faturáveis.

  4. Confirme se a listagem está configurada corretamente.

Nota

Ao testar o Custom Event Billing, você deverá configurar uma forma de pagamento mas você não será cobrado pelo uso em sua organização.

Validação se os procedimentos armazenados podem emitir eventos faturáveis

Enquanto estiver conectado à conta do consumidor com a qual você compartilhou sua listagem, chame os procedimentos armazenados que você adicionou ao seu Snowflake Native App.

Por exemplo, para testar o procedimento armazenado criado para cobrança baseada em linhas ativas mensais, faça o seguinte:

  1. Entre na conta do consumidor em Snowsight.

  2. Abra uma planilha e defina o contexto para db_1.public.

  3. Execute a seguinte instrução SQL:

    CALL merge_procedure()
    
    Copy

    Se o procedimento armazenado retornar Success, seu código está funcionando.

Nota

Se você executar esses comandos SQL na conta do provedor usada para criar o pacote de aplicativo, verá um erro.

Validação do plano de preços do Custom Event Billing

Para validar a experiência do consumidor de um Snowflake Native App e confirmar se a listagem e o pacote de aplicativo estão configurados corretamente, você pode consultar a exibição MARKETPLACE_PAID_USAGE_DAILY no esquema DATA_SHARING_USAGE do banco de dados SNOWFLAKE compartilhado.

Nota

Devido à latência na exibição, execute essas consultas pelo menos dois dias após o primeiro uso do Snowflake Native App.

Para confirmar se os eventos faturáveis foram gerados com sucesso por um Snowflake Native App e uma listagem, execute a seguinte instrução SQL na conta de consumidor com a qual você compartilhou a listagem:

Nota

Substitua os valores PROVIDER_ACCOUNT_NAME e PROVIDER_ORGANIZATION_NAME pelos da conta do provedor.

SELECT listing_global_name,
   listing_display_name,
   charge_type,
   charge
FROM SNOWFLAKE.DATA_SHARING_USAGE.MARKETPLACE_PAID_USAGE_DAILY
WHERE charge_type='MONETIZABLE_BILLING_EVENTS'
      AND PROVIDER_ACCOUNT_NAME = <account_name>
      AND PROVIDER_ORGANIZATION_NAME= <organization_name>;
Copy
+---------------------+------------------------+----------------------------+--------+
| LISTING_GLOBAL_NAME |  LISTING_DISPLAY_NAME  |        CHARGE_TYPE         | CHARGE |
+---------------------+------------------------+----------------------------+--------+
| AAAA0BBB1CC         | Snowy Mountain Listing | MONETIZABLE_BILLING_EVENTS |   18.6 |
+---------------------+------------------------+----------------------------+--------+

Para ver todos os detalhes associados ao plano de preços da listagem e validar se o plano corresponde às cobranças do aplicativo, execute a seguinte instrução SQL na conta do consumidor com a qual você compartilhou sua listagem:

Nota

Os campos anexados com pp representam campos especificados apenas na listagem como parte do plano de preços.

SELECT
    listing_display_name,
    listing_global_name,
    be.value:display_name::varchar as class_name,
    be.value:class::varchar as class,
    units,
    be.value:billing_unit::varchar as billing_unit,
    unit_price,
    charge,
    be.value:billing_quantity::float as pp_billing_quantity
FROM
    SNOWFLAKE.DATA_SHARING_USAGE.MARKETPLACE_PAID_USAGE_DAILY,
    LATERAL FLATTEN(INPUT => pricing_plan:billing_events) be
WHERE
    charge_type = 'MONETIZABLE_BILLING_EVENTS'
    AND PROVIDER_ACCOUNT_NAME = <account_name>
    AND PROVIDER_ORGANIZATION_NAME= <organization_name>;
Copy
+------------------------+---------------------+-------------+---------------+-------+--------------+------------+--------+---------------------+
|  LISTING_DISPLAY_NAME  | LISTING_GLOBAL_NAME | CLASS_NAME  |     CLASS     | UNITS | BILLING_UNIT | UNIT_PRICE | CHARGE | PP_BILLING_QUANTITY |
+------------------------+---------------------+-------------+---------------+-------+--------------+------------+--------+---------------------+
| Snowy Mountain Listing | AAAA0BBB1CC         | Active Rows | ROWS_CONSUMED |  18.6 | ROW          |          1 |   18.6 |                   1 |
+------------------------+---------------------+-------------+---------------+-------+--------------+------------+--------+---------------------+