Hé Snowflake, envoie-moi un e-mail

Nov 30 2022
Snowflake peut désormais envoyer des e-mails. Créons donc une procédure stockée qui vous envoie les résultats d'une requête tous les matins, y compris s'il y a un jour férié quelque part dans le monde qui affecte vos chiffres. Snowflake peut envoyer des e-mails maintenant Pour envoyer une notification par e-mail avec Snowflake, vous n'avez plus besoin que d'un seul appel SQL : l'objectif de cet article est de lier cette fonctionnalité à un planificateur et à du code de formatage. Ainsi, chaque matin du lundi au vendredi, nous pouvons obtenir le résultats d'une requête SQL, y compris les jours fériés à venir.

Snowflake peut désormais envoyer des e-mails. Créons donc une procédure stockée qui vous envoie les résultats d'une requête tous les matins, y compris s'il y a un jour férié quelque part dans le monde qui affecte vos chiffres.

Image générée par l'IA

Snowflake peut désormais envoyer des e-mails

Pour envoyer une notification par e-mail avec Snowflake, vous n'avez plus besoin que d'un seul appel SQL :

call system$send_email(
    'my_email_int',
    '[email protected], [email protected], [email protected]',
    'This is the subject',
    'This is the body'
);

Comment notifier les utilisateurs dans Snowflake ? ❄️ Flocon de neige en bref - Notifications par e-mail

L'objectif de cet article est de lier cette fonctionnalité à un planificateur et à du code de formatage. Ainsi, chaque matin du lundi au vendredi, nous pouvons obtenir les résultats d'une requête SQL, y compris les jours fériés à venir. Comme celui-ci:

Un e-mail envoyé par Snowflake, avec les vacances à venir

Étape 1 : Développer une procédure stockée qui formate et envoie par e-mail le résultat de toute requête

Voici le code que j'ai écrit, tout en déboguant mes capacités à envoyer par e-mail un résultat de requête bien formaté :

with pretty_email_results as procedure()
returns string
language python
packages = ('snowflake-snowpark-python', 'tabulate')
handler = 'x'
as
$$
def x(session):
    printed = session.sql(
        "select * from table(result_scan(last_query_id(-1)))"
      ).to_pandas().to_markdown()
    session.call('system$send_email',
        'my_email_int',
        '[email protected]',
        'Email Alert: Task A has finished.',
        printed)
$$
call pretty_email_results();

  • Snowflake dispose désormais de « procédures anonymes » qui vous permettent de les définir et de les appeler en une seule étape. Vous n'avez pas besoin create or replacede premier et callplus tard, ce qui est particulièrement utile lors du débogage.
  • J'ai choisi d'écrire cette procédure en Python, pour utiliser la librairie tabulate. Cette bibliothèque formatera les résultats d'une requête, afin qu'ils soient jolis sur notre courrier électronique sortant.
  • La tabulatebibliothèque est déjà fournie par Anaconda dans Snowflake, nous pouvons donc l'utiliser avec la ligne packages = (‘tabulate’).
  • Avec result_scan(last_query_id(-1)Snowflake, vous pouvez accéder aux résultats de la dernière requête exécutée, ce qui permet pretty_email_results()d'envoyer par e-mail les résultats obtenus à l'étape précédente.
  • Snowpark nous donne l' sessionobjet dans notre procédure stockée, que nous pouvons utiliser pour exécuter l'analyse des résultats avec session.sql().
  • session.sql()nous donne un Snowpark DataFrame, et l'appeler nous donne .to_pandas()Pandas DataFrame. Pandas .to_markdown()peut alors appeler tabulate- et il se plaindra à moins que vous ne demandiez pas explicitement ce paquet avec packages=(...).

Une fois votre débogage interactif terminé, vous pouvez déplacer le code vers une procédure stockée permanente :

create or replace procedure email_last_results(send_to string, subject string)
returns string
language python
runtime_version=3.8
packages = ('snowflake-snowpark-python', 'tabulate')
handler = 'x'
execute as caller
as
$$
import snowflake

def x(session, send_to, subject):
    try: 
        body = session.sql(
          "select * from table(result_scan(last_query_id(-1))) limit 100"
        ).to_pandas().to_markdown()
    except snowflake.snowpark.exceptions.SnowparkSQLException as e:
        body = '%s\n%s' % (type(e), e)
    session.call('system$send_email',
        'my_email_int',
        send_to,
        subject,
        body)
    return 'email sent:\n%s' % body
$$;

  • execute as callerest nécessaire ici pour que la procédure stockée puisse trouver l'historique des requêtes de l'utilisateur qui l'appelle.
  • runtime_version=3.8doit être explicite dans une procédure stockée permanente.
  • J'ai ajouté du code pour intercepter les exceptions et envoyer quand même un joli e-mail.
  • J'ai déplacé le sujet et les destinataires vers les arguments de la procédure.
  • J'ai ajouté un limit 100pour empêcher l'envoi d'e-mails de la taille d'un To.

call email_last_results('[email protected]', 'results from snowflake');

Désormais, une simple procédure stockée SQL peut exécuter une requête et demander à notre procédure Python d'envoyer les résultats par e-mail :

create or replace procedure run_query_and_email_it()
returns string
execute as caller
as
$$
begin
    -- any query you'd like to run
    select 'now' as what, to_char(current_timestamp) as value
    union all
    select 'upcoming', day || ' ' ||holiday
    from table(fh_db.public.holidays('US', [year(current_date), year(current_date)+1]))
    where day between current_date() and current_date()+60
    ;
    -- call the stored procedure that formats and emails the results
    call email_last_results('[email protected]', 'upcoming holidays');
    return 'done';
end
$$
;

call run_query_and_email_it();

Snowflake a un planificateur de tâches prêt pour vos demandes :

create or replace task email_me_frequently
warehouse = 's'
schedule = 'using cron 0 8 * * 1-5 America/Los_Angeles'
as call run_query_and_email_it();

Quelques notes:

  • Je lui ai demandé d'utiliser mon entrepôt appelé "s". Snowflake propose également des tâches sans serveur , mais celles-ci n'exécutent pas de procédures stockées Python.
  • J'ai dû modifier mon holidays()UDF en déplaçant les .zipdépendances Python d'une étape utilisateur vers une étape nommée . Quand il vivait à l'intérieur de ma scène utilisateur, la tâche a généré l'erreur Remote file ‘holidays.zip’ was not found.
  • Changez la planification en chaque 1 minutesi vous avez besoin de déboguer.

alter task email_me_frequently resume;

select *
  from table(information_schema.task_history(
    scheduled_time_range_start=>dateadd('hour',-48,current_timestamp()),
    result_limit => 100));

      
                
Images generated by AI

Ne vous inquiétez pas trop de la création d'un système d'alerte - Snowflake est déjà en train de le développer ( actuellement en préversion privée ) :

CREATE ALERT Warehouse_Credit_Usage_Alert
 WAREHOUSE = my_warehouse
 SCHEDULE = ‘USING CRON 0 7 * * *UTC’ // everyday at 7 am
 IF (EXISTS (SELECT
  Warehouse_name,
  SUM(CREDITS_USED) AS credits
  FROM snowflake.account_usage.warehouse_metering_history
  // aggregate warehouse Credit_used for the past 24 hours
 WHERE datediff(hour, start_time, CURRENT_TIMESTAMP ())<=24
 GROUP BY 1
 HAVING credits > 10
 ORDER BY 2 DESC))
 THEN system$send_email (
  ‘My_email_notification_integration’, 
        ‘admin1@company,com, [email protected]’,
        ‘Email Alert: Excessive warehouse usage!’, 
        ‘Warehouse usage exceeds 10 credits in the past 24 hours’
)

  • Essayez ceci avec un compte d'essai gratuit Snowflake - vous n'avez besoin que d'une adresse e-mail pour commencer.
  • Jouez avec les options de formatage qu'offre tabulate.
Images générées par l'IA