@@ -1446,6 +1446,37 @@ func handleDailyCacheUpdate(executionInfo *ExecutionInfo) *ExecutionInfo {
14461446 return executionInfo
14471447}
14481448
1449+ func generateAlertCacheKey (orgId string , threshold interface {}, emailList []string ) string {
1450+ sortedEmails := make ([]string , len (emailList ))
1451+ copy (sortedEmails , emailList )
1452+ sort .Strings (sortedEmails )
1453+
1454+ emailsStr := strings .Join (sortedEmails , "," )
1455+ thresholdStr := fmt .Sprintf ("%v" , threshold )
1456+
1457+ key := fmt .Sprintf ("alert_cache_%s_%s_%s" , orgId , thresholdStr , emailsStr )
1458+
1459+ key = strings .ReplaceAll (key , "@" , "_at_" )
1460+ key = strings .ReplaceAll (key , "." , "_dot_" )
1461+ key = strings .ReplaceAll (key , " " , "_" )
1462+
1463+ return key
1464+ }
1465+
1466+ func checkAndSetAlertCache (ctx context.Context , cacheKey string ) bool {
1467+ _ , err := GetCache (ctx , cacheKey )
1468+ if err == nil {
1469+ return false
1470+ }
1471+
1472+ err = SetCache (ctx , cacheKey , []byte ("sent" ), 60 )
1473+ if err != nil {
1474+ log .Printf ("[WARNING] Failed setting alert cache for key %s: %s" , cacheKey , err )
1475+ }
1476+
1477+ return true
1478+ }
1479+
14491480func HandleIncrement (dataType string , orgStatistics * ExecutionInfo , increment uint ) * ExecutionInfo {
14501481
14511482 appendCustom := false
@@ -1650,6 +1681,19 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
16501681 firstAdmin = allAdmins [0 ]
16511682 }
16521683
1684+ if ! ArrayContains (
allAdmins ,
"[email protected] " ) {
1685+ allAdmins = append (
allAdmins ,
"[email protected] " )
1686+ }
1687+
1688+ if ! ArrayContains (
allAdmins ,
"[email protected] " ) {
1689+ allAdmins = append (
allAdmins ,
"[email protected] " )
1690+ }
1691+
1692+ cacheKey := generateAlertCacheKey (orgId , AlertThreshold .Count , allAdmins )
1693+ if ! checkAndSetAlertCache (ctx , cacheKey ) {
1694+ continue
1695+ }
1696+
16531697 Subject := fmt .Sprintf ("[Shuffle]: You've reached the app-runs threshold limit for your account %s" , firstAdmin )
16541698
16551699 AppRunsPercentage := float64 (totalAppExecutions ) / float64 (org .SyncFeatures .AppExecutions .Limit ) * 100
@@ -1663,14 +1707,6 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
16631707 "admin_email" : firstAdmin ,
16641708 }
16651709
1666- if ! ArrayContains (
allAdmins ,
"[email protected] " ) {
1667- allAdmins = append (
allAdmins ,
"[email protected] " )
1668- }
1669-
1670- if ! ArrayContains (
allAdmins ,
"[email protected] " ) {
1671- allAdmins = append (
allAdmins ,
"[email protected] " )
1672- }
1673-
16741710 err = sendMailSendgridV2 (
1675171116761712 Subject ,
@@ -1709,25 +1745,6 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
17091745 // hard limit aleart
17101746 if org .Billing .AppRunsHardLimit > 0 && orgStatistics .MonthlyAppExecutions > org .Billing .AppRunsHardLimit {
17111747 // send alert to all admin in the orgs
1712- subject := fmt .Sprintf ("App Runs Hard Limit Exceeded for Org %s (%s)" , org .Name , org .Id )
1713- message := fmt .Sprintf (
1714- `Dear Team,
1715-
1716- Your organization <strong>%s</strong> (ID: %s) has exceeded the monthly app runs hard limit of <strong>%d</strong> runs.
1717-
1718- <strong>Current usage:</strong> %d app runs.
1719-
1720- As a result, all workflows have been temporarily blocked until the start of the next billing cycle.
1721- To increase your organization's hard limit, please visit the admin panel of the parent organization.
1722- If you have any questions, feel free to reach out to us at <a href="mailto:[email protected] ">[email protected] </a>. 1723-
1724- Note: This is an automated message sent by Shuffle to notify you about the exceeded app runs hard limit.
1725-
1726- Best regards,
1727- The Shuffler Team` ,
1728- org .Name , org .Id , org .Billing .AppRunsHardLimit , orgStatistics .MonthlyAppExecutions ,
1729- )
1730-
17311748 admins := []string {}
17321749
17331750 for _ , user := range org .Users {
@@ -1736,9 +1753,33 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
17361753 }
17371754 }
17381755
1739- err = sendMailSendgrid (admins , subject , message , false , []string {})
1740- if err != nil {
1741- log .Printf ("[ERROR] Failed sending alert email to admins of org %s (%s): %s" , org .Name , org .Id , err )
1756+ cacheKey := generateAlertCacheKey (orgId , "hard_limit" , admins )
1757+ if ! checkAndSetAlertCache (ctx , cacheKey ) {
1758+ log .Printf ("[DEBUG] Skipping duplicate hard limit alert for org %s - alert sent within last minute" , orgId )
1759+ } else {
1760+ subject := fmt .Sprintf ("App Runs Hard Limit Exceeded for Org %s (%s)" , org .Name , org .Id )
1761+ message := fmt .Sprintf (
1762+ `Dear Team,
1763+
1764+ Your organization <strong>%s</strong> (ID: %s) has exceeded the monthly app runs hard limit of <strong>%d</strong> runs.
1765+
1766+ <strong>Current usage:</strong> %d app runs.
1767+
1768+ As a result, all workflows have been temporarily blocked until the start of the next billing cycle.
1769+ To increase your organization's hard limit, please visit the admin panel of the parent organization.
1770+ If you have any questions, feel free to reach out to us at <a href="mailto:[email protected] ">[email protected] </a>. 1771+
1772+ Note: This is an automated message sent by Shuffle to notify you about the exceeded app runs hard limit.
1773+
1774+ Best regards,
1775+ The Shuffler Team` ,
1776+ org .Name , org .Id , org .Billing .AppRunsHardLimit , orgStatistics .MonthlyAppExecutions ,
1777+ )
1778+
1779+ err = sendMailSendgrid (admins , subject , message , false , []string {})
1780+ if err != nil {
1781+ log .Printf ("[ERROR] Failed sending alert email to admins of org %s (%s): %s" , org .Name , org .Id , err )
1782+ }
17421783 }
17431784 }
17441785
@@ -1835,56 +1876,87 @@ func HandleIncrement(dataType string, orgStatistics *ExecutionInfo, increment ui
18351876 Subject = fmt .Sprintf ("[Shuffle] %s: You've reached the app-runs threshold limit for your account %s" , leadInfo , firstAdmin )
18361877 }
18371878
1838- totalAppExecutions := validationOrgStatistics .MonthlyAppExecutions + validationOrgStatistics .MonthlyChildAppExecutions
1839- AppRunsPercentage := float64 (totalAppExecutions ) / float64 (validationOrg .SyncFeatures .AppExecutions .Limit ) * 100
1840-
1841- substitutions := map [string ]interface {}{
1842- "app_runs_usage" : totalAppExecutions ,
1843- "app_runs_limit" : validationOrg .SyncFeatures .AppExecutions .Limit ,
1844- "app_runs_usage_percentage" : int64 (AppRunsPercentage ),
1845- "org_name" : validationOrg .Name ,
1846- "org_id" : validationOrg .Id ,
1847- "admin_email" : firstAdmin ,
1879+ if len (
leadInfo )
== 0 && ! ArrayContains (
newEmailList ,
"[email protected] " ) {
1880+ newEmailList = append (
newEmailList ,
"[email protected] " )
18481881 }
18491882
1850- if currentThreshold > 100 {
1851- substitutions [ "lead_info" ] = leadInfo
1883+ if len ( leadInfo ) == 0 && ! ArrayContains ( newEmailList , "[email protected] " ) {
1884+ newEmailList = append ( newEmailList , "[email protected] " ) 18521885 }
18531886
1854- err = sendMailSendgridV2 (
1855- 1856- Subject ,
1857- substitutions ,
1858- false ,
1859- "d-3678d48b2b7144feb4b0b4cff7045016" ,
1860- newEmailList ,
1861- )
1862-
1863- if err != nil {
1864- log .Printf ("[ERROR] Failed sending alert mail for child org in increment (1): %s" , err )
1887+ cacheKey := generateAlertCacheKey (validationOrg .Id , currentThreshold , newEmailList )
1888+ if ! checkAndSetAlertCache (ctx , cacheKey ) {
1889+ log .Printf ("[DEBUG] Skipping duplicate percentage threshold alert for org %s, threshold %d%% - alert sent within last minute" , validationOrg .Id , currentThreshold )
18651890 } else {
1866- log .Printf ("[DEBUG] Successfully sent alert mail for child org %s to parent org %s (1)" , validationOrg .Name , validationOrg .Name )
1867- }
1868-
1869- if currentThreshold == 100 || currentThreshold == 50 {
1870- if len (leadInfo ) > 0 {
1871- Subject = fmt .Sprintf ("[Shuffle] %s: You've reached the app-runs threshold limit for your account %s" , leadInfo , firstAdmin )
1891+ totalAppExecutions := validationOrgStatistics .MonthlyAppExecutions + validationOrgStatistics .MonthlyChildAppExecutions
1892+ AppRunsPercentage := float64 (totalAppExecutions ) / float64 (validationOrg .SyncFeatures .AppExecutions .Limit ) * 100
1893+
1894+ substitutions := map [string ]interface {}{
1895+ "app_runs_usage" : totalAppExecutions ,
1896+ "app_runs_limit" : validationOrg .SyncFeatures .AppExecutions .Limit ,
1897+ "app_runs_usage_percentage" : int64 (AppRunsPercentage ),
1898+ "org_name" : validationOrg .Name ,
1899+ "org_id" : validationOrg .Id ,
1900+ "admin_email" : firstAdmin ,
18721901 }
18731902
1874- substitutions ["lead_info" ] = leadInfo
1903+ if currentThreshold > 100 {
1904+ substitutions ["lead_info" ] = leadInfo
1905+ }
18751906
18761907 err = sendMailSendgridV2 (
1877- 1908+ 18781909 Subject ,
18791910 substitutions ,
18801911 false ,
18811912 "d-3678d48b2b7144feb4b0b4cff7045016" ,
1882- [] string {} ,
1913+ newEmailList ,
18831914 )
1915+
18841916 if err != nil {
1885- log .Printf ("[ERROR] Failed sending alert mail for child org in increment (2): %s" , err )
1917+ log .Printf ("[ERROR] Failed sending alert mail for child org in increment (1): %s" , err )
1918+ } else {
1919+ log .Printf ("[DEBUG] Successfully sent alert mail for child org %s to parent org %s (1)" , validationOrg .Name , validationOrg .Name )
1920+ }
1921+ }
1922+
1923+ if (currentThreshold == 100 || currentThreshold == 50 ) && len (leadInfo ) > 0 {
1924+ 1925+ secondCacheKey := generateAlertCacheKey (validationOrg .Id , fmt .Sprintf ("second_%d" , currentThreshold ), secondEmailList )
1926+ if ! checkAndSetAlertCache (ctx , secondCacheKey ) {
1927+ log .Printf ("[DEBUG] Skipping duplicate second alert for org %s, threshold %d%% - alert sent within last minute" , validationOrg .Id , currentThreshold )
18861928 } else {
1887- log .Printf ("[DEBUG] Successfully sent alert mail for child org %s to parent org %s (2)" , validationOrg .Name , validationOrg .Name )
1929+ if len (leadInfo ) > 0 {
1930+ Subject = fmt .Sprintf ("[Shuffle] %s: You've reached the app-runs threshold limit for your account %s" , leadInfo , firstAdmin )
1931+ }
1932+
1933+ totalAppExecutions := validationOrgStatistics .MonthlyAppExecutions + validationOrgStatistics .MonthlyChildAppExecutions
1934+ AppRunsPercentage := float64 (totalAppExecutions ) / float64 (validationOrg .SyncFeatures .AppExecutions .Limit ) * 100
1935+
1936+ substitutions := map [string ]interface {}{
1937+ "app_runs_usage" : totalAppExecutions ,
1938+ "app_runs_limit" : validationOrg .SyncFeatures .AppExecutions .Limit ,
1939+ "app_runs_usage_percentage" : int64 (AppRunsPercentage ),
1940+ "org_name" : validationOrg .Name ,
1941+ "org_id" : validationOrg .Id ,
1942+ "admin_email" : firstAdmin ,
1943+ "lead_info" : leadInfo ,
1944+ }
1945+
1946+ log .Printf ("[DEBUG] Sending second alert mail for child org %s to parent org %s (2)" , validationOrg .Name , validationOrg .Name )
1947+ err = sendMailSendgridV2 (
1948+ 1949+ Subject ,
1950+ substitutions ,
1951+ false ,
1952+ "d-3678d48b2b7144feb4b0b4cff7045016" ,
1953+ []string {},
1954+ )
1955+ if err != nil {
1956+ log .Printf ("[ERROR] Failed sending alert mail for child org in increment (2): %s" , err )
1957+ } else {
1958+ log .Printf ("[DEBUG] Successfully sent alert mail for child org %s to parent org %s (2)" , validationOrg .Name , validationOrg .Name )
1959+ }
18881960 }
18891961 }
18901962
0 commit comments