mage-ai 0.9.75__py3-none-any.whl → 0.9.77__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mage-ai might be problematic. Click here for more details.

Files changed (226) hide show
  1. mage_ai/api/policies/PipelineSchedulePolicy.py +1 -0
  2. mage_ai/api/presenters/PipelineSchedulePresenter.py +11 -2
  3. mage_ai/api/resources/GitFileResource.py +8 -0
  4. mage_ai/api/resources/PipelineScheduleResource.py +11 -3
  5. mage_ai/api/resources/PipelineTriggerResource.py +3 -1
  6. mage_ai/api/resources/SessionResource.py +2 -2
  7. mage_ai/api/resources/SyncResource.py +1 -1
  8. mage_ai/api/resources/UserResource.py +1 -1
  9. mage_ai/cli/main.py +6 -1
  10. mage_ai/data_integrations/destinations/constants.py +2 -0
  11. mage_ai/data_integrations/sources/constants.py +2 -0
  12. mage_ai/data_preparation/executors/block_executor.py +8 -3
  13. mage_ai/data_preparation/executors/pipeline_executor.py +35 -19
  14. mage_ai/data_preparation/models/block/__init__.py +29 -23
  15. mage_ai/data_preparation/models/block/dbt/dbt_adapter.py +20 -8
  16. mage_ai/data_preparation/models/block/dynamic/constants.py +0 -1
  17. mage_ai/data_preparation/models/block/dynamic/counter.py +1 -3
  18. mage_ai/data_preparation/models/block/outputs.py +1 -1
  19. mage_ai/data_preparation/models/block/r/__init__.py +16 -5
  20. mage_ai/data_preparation/models/block/sql/__init__.py +2 -0
  21. mage_ai/data_preparation/models/block/sql/mssql.py +8 -0
  22. mage_ai/data_preparation/models/block/sql/utils/shared.py +6 -2
  23. mage_ai/data_preparation/models/constants.py +3 -0
  24. mage_ai/data_preparation/models/pipeline.py +1 -1
  25. mage_ai/data_preparation/storage/local_storage.py +4 -1
  26. mage_ai/data_preparation/templates/constants.py +7 -0
  27. mage_ai/data_preparation/templates/data_loaders/airtable.py +28 -0
  28. mage_ai/data_preparation/templates/repo/io_config.yaml +2 -0
  29. mage_ai/io/airtable.py +104 -0
  30. mage_ai/io/base.py +1 -0
  31. mage_ai/io/bigquery.py +36 -0
  32. mage_ai/io/config.py +6 -0
  33. mage_ai/io/mssql.py +21 -9
  34. mage_ai/io/mysql.py +6 -1
  35. mage_ai/io/postgres.py +3 -0
  36. mage_ai/io/redshift.py +13 -0
  37. mage_ai/io/sql.py +1 -0
  38. mage_ai/orchestration/db/__init__.py +20 -0
  39. mage_ai/orchestration/db/migrations/versions/39d36f1dab73_create_genericjob.py +47 -0
  40. mage_ai/orchestration/db/models/oauth.py +2 -1
  41. mage_ai/orchestration/db/models/schedules.py +107 -5
  42. mage_ai/orchestration/db/models/secrets.py +11 -1
  43. mage_ai/orchestration/job_manager.py +19 -0
  44. mage_ai/orchestration/metrics/pipeline_run.py +1 -1
  45. mage_ai/orchestration/notification/sender.py +2 -2
  46. mage_ai/orchestration/pipeline_scheduler_original.py +150 -6
  47. mage_ai/orchestration/pipeline_scheduler_project_platform.py +4 -5
  48. mage_ai/orchestration/queue/config.py +11 -1
  49. mage_ai/orchestration/queue/process_queue.py +2 -0
  50. mage_ai/orchestration/utils/distributed_lock.py +8 -1
  51. mage_ai/server/api/base.py +41 -0
  52. mage_ai/server/api/constants.py +1 -0
  53. mage_ai/server/api/triggers.py +9 -0
  54. mage_ai/server/constants.py +1 -1
  55. mage_ai/server/frontend_dist/404.html +2 -2
  56. mage_ai/server/frontend_dist/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
  57. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-782dd4a6b13e1c42.js +2 -0
  58. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
  59. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
  60. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-03d9bca3bc5e6088.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-d25d07db166cbb04.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-0bc44da590c7cf85.js → webpack-b9a067f3bd0a3a05.js} +1 -1
  64. mage_ai/server/frontend_dist/_next/static/{38-PtskJFUTYUpRhT1qF_ → qR0jauUABqPaFMjUsYeoG}/_buildManifest.js +1 -1
  65. mage_ai/server/frontend_dist/block-layout.html +2 -2
  66. mage_ai/server/frontend_dist/compute.html +2 -2
  67. mage_ai/server/frontend_dist/files.html +2 -2
  68. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  69. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  70. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  71. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  72. mage_ai/server/frontend_dist/index.html +2 -2
  73. mage_ai/server/frontend_dist/manage/files.html +2 -2
  74. mage_ai/server/frontend_dist/manage/overview.html +2 -2
  75. mage_ai/server/frontend_dist/manage/pipeline-runs.html +2 -2
  76. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  77. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  78. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  79. mage_ai/server/frontend_dist/manage/users.html +2 -2
  80. mage_ai/server/frontend_dist/manage.html +2 -2
  81. mage_ai/server/frontend_dist/oauth.html +3 -3
  82. mage_ai/server/frontend_dist/overview.html +2 -2
  83. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  84. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  85. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  86. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  87. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  88. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  89. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  90. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  91. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  92. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  93. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  94. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  95. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  96. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  97. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  98. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  99. mage_ai/server/frontend_dist/pipelines.html +2 -2
  100. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  101. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  102. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  103. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  104. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  105. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  106. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  107. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  108. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  109. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  110. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  111. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  112. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  113. mage_ai/server/frontend_dist/settings.html +2 -2
  114. mage_ai/server/frontend_dist/sign-in.html +5 -5
  115. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  116. mage_ai/server/frontend_dist/templates.html +2 -2
  117. mage_ai/server/frontend_dist/terminal.html +2 -2
  118. mage_ai/server/frontend_dist/test.html +2 -2
  119. mage_ai/server/frontend_dist/triggers.html +2 -2
  120. mage_ai/server/frontend_dist/v2/canvas.html +2 -2
  121. mage_ai/server/frontend_dist/v2.html +2 -2
  122. mage_ai/server/frontend_dist/version-control.html +2 -2
  123. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  124. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/449-5e2253c6aba42557.js +1 -0
  125. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-ee5e328aaf51c698.js +2 -0
  126. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-5db54821a3059c69.js +1 -0
  127. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-f65416f6dbe30ad3.js +1 -0
  128. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-03d9bca3bc5e6088.js +1 -0
  129. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-d25d07db166cbb04.js +1 -0
  130. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-fa61dc6c1370e6a5.js +1 -0
  131. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-12ad70eb5c31aa92.js → webpack-5f4be622608d9267.js} +1 -1
  132. mage_ai/server/frontend_dist_base_path_template/_next/static/{dxnSzgIvSG4Ke5LM-tPQX → iCySon3_GCldnbC5U7C-s}/_buildManifest.js +1 -1
  133. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  134. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  135. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  136. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  137. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  138. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  139. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  140. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  141. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  142. mage_ai/server/frontend_dist_base_path_template/manage/overview.html +2 -2
  143. mage_ai/server/frontend_dist_base_path_template/manage/pipeline-runs.html +2 -2
  144. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  145. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  146. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  147. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  148. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  149. mage_ai/server/frontend_dist_base_path_template/oauth.html +3 -3
  150. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  151. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  152. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  153. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  154. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  155. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  156. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  157. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  158. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  159. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  160. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  161. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  162. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  163. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  164. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  165. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  166. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  167. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  168. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  169. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  172. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  173. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  181. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/sign-in.html +5 -5
  183. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  188. mage_ai/server/frontend_dist_base_path_template/v2/canvas.html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/v2.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  191. mage_ai/server/scheduler_manager.py +2 -0
  192. mage_ai/server/terminal_server.py +3 -0
  193. mage_ai/settings/server.py +4 -0
  194. mage_ai/streaming/sources/kafka.py +2 -1
  195. mage_ai/tests/data_preparation/executors/test_block_executor.py +3 -3
  196. mage_ai/tests/data_preparation/models/block/dynamic/test_counter.py +1 -3
  197. mage_ai/tests/data_preparation/models/test_variable.py +2 -0
  198. mage_ai/tests/io/create_table/test_postgresql.py +3 -2
  199. mage_ai/tests/orchestration/notification/test_sender.py +5 -1
  200. mage_ai/tests/streaming/sources/test_kafka.py +2 -2
  201. mage_ai/usage_statistics/logger.py +99 -15
  202. mage_ai-0.9.77.dist-info/METADATA +356 -0
  203. {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/RECORD +211 -208
  204. {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/WHEEL +1 -1
  205. mage_ai/server/frontend_dist/_next/static/chunks/449-f689774546860ca4.js +0 -1
  206. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-13bf3b7dcef50c29.js +0 -2
  207. mage_ai/server/frontend_dist/_next/static/chunks/pages/manage/users-b99379d0aa6a8c25.js +0 -1
  208. mage_ai/server/frontend_dist/_next/static/chunks/pages/overview-e51cd04bd4d1fffe.js +0 -1
  209. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-0abf8a1b7243f93b.js +0 -1
  210. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-38187954b6ec4b40.js +0 -1
  211. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/users-3ee783f5139c76a1.js +0 -1
  212. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/449-f689774546860ca4.js +0 -1
  213. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-0392ef723ea2c6f8.js +0 -2
  214. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage/users-b99379d0aa6a8c25.js +0 -1
  215. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/overview-e51cd04bd4d1fffe.js +0 -1
  216. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-0abf8a1b7243f93b.js +0 -1
  217. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-38187954b6ec4b40.js +0 -1
  218. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/users-3ee783f5139c76a1.js +0 -1
  219. mage_ai-0.9.75.dist-info/METADATA +0 -377
  220. /mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-13bf3b7dcef50c29.js.LICENSE.txt → _app-782dd4a6b13e1c42.js.LICENSE.txt} +0 -0
  221. /mage_ai/server/frontend_dist/_next/static/{38-PtskJFUTYUpRhT1qF_ → qR0jauUABqPaFMjUsYeoG}/_ssgManifest.js +0 -0
  222. /mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{_app-0392ef723ea2c6f8.js.LICENSE.txt → _app-ee5e328aaf51c698.js.LICENSE.txt} +0 -0
  223. /mage_ai/server/frontend_dist_base_path_template/_next/static/{dxnSzgIvSG4Ke5LM-tPQX → iCySon3_GCldnbC5U7C-s}/_ssgManifest.js +0 -0
  224. {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/entry_points.txt +0 -0
  225. {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info/licenses}/LICENSE +0 -0
  226. {mage_ai-0.9.75.dist-info → mage_ai-0.9.77.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ class JobType(StrEnum):
8
8
  BLOCK_RUN = 'block_run'
9
9
  PIPELINE_RUN = 'pipeline_run'
10
10
  INTEGRATION_STREAM = 'integration_stream'
11
+ GENERIC_JOB = 'generic_job'
11
12
 
12
13
 
13
14
  class JobManager:
@@ -62,6 +63,19 @@ class JobManager:
62
63
  logging_tags=logging_tags,
63
64
  )
64
65
 
66
+ def has_generic_job(
67
+ self,
68
+ generic_job_id: int,
69
+ logger=None,
70
+ logging_tags: Dict = None,
71
+ ) -> bool:
72
+ job_id = self.__job_id(JobType.GENERIC_JOB, generic_job_id)
73
+ return self.queue.has_job(
74
+ job_id,
75
+ logger=logger,
76
+ logging_tags=logging_tags,
77
+ )
78
+
65
79
  def kill_block_run_job(self, block_run_id):
66
80
  print(f'Kill block run id: {block_run_id}')
67
81
  job_id = self.__job_id(JobType.BLOCK_RUN, block_run_id)
@@ -78,6 +92,11 @@ class JobManager:
78
92
  job_id = self.__job_id(JobType.INTEGRATION_STREAM, id)
79
93
  return self.queue.kill_job(job_id)
80
94
 
95
+ def kill_generic_job(self, generic_job_id):
96
+ print(f'Kill generic job id: {generic_job_id}')
97
+ job_id = self.__job_id(JobType.GENERIC_JOB, generic_job_id)
98
+ return self.queue.kill_job(job_id)
99
+
81
100
  def start(self):
82
101
  self.queue.start()
83
102
 
@@ -220,7 +220,7 @@ def __calculate_metrics(pipeline_run: PipelineRun, pipeline) -> Dict:
220
220
 
221
221
  pipeline_metrics_by_stream = {}
222
222
  pipeline_logs_by_stream = {}
223
- pipeline_logs = pipeline_run.logs['content'].split('\n')
223
+ pipeline_logs = pipeline_run.logs[0]['content'].split('\n')
224
224
  for pipeline_log in pipeline_logs:
225
225
  tags = parse_line(pipeline_log)
226
226
  stream = tags.get('stream')
@@ -69,7 +69,7 @@ class NotificationSender:
69
69
 
70
70
  if self.config.teams_config is not None and self.config.teams_config.is_valid:
71
71
  try:
72
- send_teams_message(self.config.teams_config, summary)
72
+ send_teams_message(self.config.teams_config, summary, title)
73
73
  except Exception:
74
74
  traceback.print_exc()
75
75
 
@@ -87,7 +87,7 @@ class NotificationSender:
87
87
 
88
88
  if self.config.google_chat_config is not None and self.config.google_chat_config.is_valid:
89
89
  try:
90
- send_google_chat_message(self.config.google_chat_config, summary)
90
+ send_google_chat_message(self.config.google_chat_config, summary, title)
91
91
  except Exception:
92
92
  traceback.print_exc()
93
93
 
@@ -1,4 +1,3 @@
1
- import asyncio
2
1
  import collections
3
2
  import os
4
3
  import traceback
@@ -33,6 +32,7 @@ from mage_ai.orchestration.db.models.schedules import (
33
32
  Backfill,
34
33
  BlockRun,
35
34
  EventMatcher,
35
+ GenericJob,
36
36
  PipelineRun,
37
37
  PipelineSchedule,
38
38
  )
@@ -260,7 +260,7 @@ class PipelineScheduler:
260
260
  pipeline=self.pipeline,
261
261
  pipeline_run=self.pipeline_run,
262
262
  )
263
- asyncio.run(UsageStatisticLogger().pipeline_run_ended(self.pipeline_run))
263
+ UsageStatisticLogger().pipeline_run_ended_sync(self.pipeline_run)
264
264
 
265
265
  self.logger_manager.output_logs_to_destination()
266
266
 
@@ -339,7 +339,7 @@ class PipelineScheduler:
339
339
  error_msg: str,
340
340
  status=PipelineRun.PipelineRunStatus.FAILED,
341
341
  ) -> None:
342
- asyncio.run(UsageStatisticLogger().pipeline_run_ended(self.pipeline_run))
342
+ UsageStatisticLogger().pipeline_run_ended_sync(self.pipeline_run)
343
343
 
344
344
  if status == PipelineRun.PipelineRunStatus.FAILED:
345
345
  # Only send notification when pipeline run status is FAILED
@@ -929,6 +929,81 @@ class PipelineScheduler:
929
929
  self.memory_usage_failure(tags=tags)
930
930
 
931
931
 
932
+ def on_pipeline_run_cancelled(
933
+ job_id: int,
934
+ pipeline_run_id: int,
935
+ cancelled_block_run_ids: List,
936
+ ):
937
+ job = GenericJob.query.get(job_id)
938
+ if job.status not in [
939
+ GenericJob.JobStatus.INITIAL,
940
+ GenericJob.JobStatus.QUEUED,
941
+ GenericJob.JobStatus.RUNNING,
942
+ ]:
943
+ return
944
+ job.mark_running()
945
+
946
+ if not pipeline_run_id:
947
+ job.mark_failed(
948
+ metadata=dict(
949
+ error_message='Pipeline run id is not provided in the job.',
950
+ ),
951
+ )
952
+ return
953
+ if not cancelled_block_run_ids:
954
+ job.mark_failed(
955
+ metadata=dict(
956
+ error_message='Cancelled block run ids are not provided in the job.',
957
+ ),
958
+ )
959
+ return
960
+
961
+ try:
962
+ # Run callback blocks for cancelled block runs
963
+ pipeline_run = PipelineRun.query.get(pipeline_run_id)
964
+ if not pipeline_run:
965
+ raise Exception(f'Fail to retrieve pipeline run with id {pipeline_run_id}')
966
+ pipeline_schedule = pipeline_run.pipeline_schedule
967
+ pipeline = get_pipeline_from_platform(
968
+ pipeline_run.pipeline_uuid,
969
+ repo_path=pipeline_schedule.repo_path if pipeline_schedule else None,
970
+ )
971
+ if pipeline_run.status != PipelineRun.PipelineRunStatus.CANCELLED:
972
+ job.mark_failed(
973
+ metadata=dict(
974
+ error_message=f'Pipeline run {pipeline_run_id} is not in cancelled status.',
975
+ ),
976
+ )
977
+ return
978
+ for block_run_id in cancelled_block_run_ids:
979
+ block_run = BlockRun.query.get(block_run_id)
980
+ if not block_run:
981
+ continue
982
+ if block_run.status != BlockRun.BlockRunStatus.CANCELLED:
983
+ continue
984
+ ExecutorFactory.get_block_executor(
985
+ pipeline,
986
+ block_run.block_uuid,
987
+ block_run_id=block_run.id,
988
+ execution_partition=pipeline_run.execution_partition,
989
+ executor_type=ExecutorType.LOCAL_PYTHON,
990
+ ).execute_callback(
991
+ callback='on_cancelled',
992
+ global_vars=pipeline_run.get_variables(),
993
+ logging_tags=None,
994
+ pipeline_run=pipeline_run,
995
+ block_run_id=block_run_id,
996
+ )
997
+ except Exception as e:
998
+ job.mark_failed(
999
+ metadata=dict(
1000
+ error_message=f'Failed to run pipeline run cancellation hook: {e}.',
1001
+ ),
1002
+ )
1003
+ return
1004
+ job.mark_completed()
1005
+
1006
+
932
1007
  def run_integration_streams(
933
1008
  streams: List[Dict],
934
1009
  *args,
@@ -1372,7 +1447,7 @@ def stop_pipeline_run(
1372
1447
  # Update pipeline run status to cancelled
1373
1448
  pipeline_run.update(status=status)
1374
1449
 
1375
- asyncio.run(UsageStatisticLogger().pipeline_run_ended(pipeline_run))
1450
+ UsageStatisticLogger().pipeline_run_ended_sync(pipeline_run)
1376
1451
 
1377
1452
  # Cancel all the block runs
1378
1453
  cancel_block_runs_and_jobs(pipeline_run, pipeline)
@@ -1407,8 +1482,9 @@ def cancel_block_runs_and_jobs(
1407
1482
  block_runs_to_cancel.append(b)
1408
1483
  if b.status == BlockRun.BlockRunStatus.RUNNING:
1409
1484
  running_blocks.append(b)
1485
+ cancelled_block_run_ids = [b.id for b in block_runs_to_cancel]
1410
1486
  BlockRun.batch_update_status(
1411
- [b.id for b in block_runs_to_cancel],
1487
+ cancelled_block_run_ids,
1412
1488
  BlockRun.BlockRunStatus.CANCELLED,
1413
1489
  )
1414
1490
 
@@ -1436,6 +1512,18 @@ def cancel_block_runs_and_jobs(
1436
1512
  for b in running_blocks:
1437
1513
  job_manager.kill_block_run_job(b.id)
1438
1514
 
1515
+ GenericJob.enqueue_cancel_pipeline_run(pipeline_run.id, cancelled_block_run_ids)
1516
+
1517
+
1518
+ def kill_cancelled_runs(pipeline_run_id: int, cancelled_block_run_ids: List):
1519
+ job_manager = get_job_manager()
1520
+ if pipeline_run_id and job_manager.has_pipeline_run_job(pipeline_run_id):
1521
+ job_manager.kill_pipeline_run_job(pipeline_run_id)
1522
+ if cancelled_block_run_ids:
1523
+ for block_run_id in cancelled_block_run_ids:
1524
+ if job_manager.has_block_run_job(block_run_id):
1525
+ job_manager.kill_block_run_job(block_run_id)
1526
+
1439
1527
 
1440
1528
  def check_sla():
1441
1529
  repo_pipelines = set(
@@ -1584,7 +1672,7 @@ def schedule_all():
1584
1672
  pipeline_runs_excluded_by_limit = []
1585
1673
  for pipeline_schedule in active_schedules:
1586
1674
  lock_key = f'pipeline_schedule_{pipeline_schedule.id}'
1587
- if not lock.try_acquire_lock(lock_key):
1675
+ if not lock.try_acquire_lock(lock_key, timeout=30):
1588
1676
  continue
1589
1677
 
1590
1678
  trigger_pipeline_run_limit = pipeline_schedule.get_settings().pipeline_run_limit
@@ -1733,6 +1821,13 @@ def schedule_all():
1733
1821
  logger.exception(f'Failed to schedule {r}')
1734
1822
  traceback.print_exc()
1735
1823
  continue
1824
+
1825
+ try:
1826
+ schedule_generic_jobs()
1827
+ except Exception as e:
1828
+ logger.exception(f'Failed to schedule generic jobs {e}')
1829
+ traceback.print_exc()
1830
+
1736
1831
  job_manager = get_job_manager()
1737
1832
  if job_manager is None:
1738
1833
  logger.info('Job manager is None.')
@@ -1913,3 +2008,52 @@ def sync_schedules(pipeline_uuids: List[str]):
1913
2008
  trigger_configs.append(pipeline_trigger)
1914
2009
 
1915
2010
  PipelineSchedule.create_or_update_batch(trigger_configs)
2011
+
2012
+
2013
+ def schedule_generic_jobs():
2014
+ """
2015
+ Schedule generic jobs that are in INITIAL status.
2016
+
2017
+ This method schedules jobs like cancel_pipeline_run that have been enqueued
2018
+ by the server process and are waiting to be executed by the job manager.
2019
+ """
2020
+ try:
2021
+ # Get all jobs with INITIAL status across all repositories
2022
+ jobs = GenericJob.get_jobs_with_initial_status()
2023
+ job_manager = get_job_manager()
2024
+
2025
+ if not jobs:
2026
+ return
2027
+
2028
+ logger.info(f'Scheduling {len(jobs)} generic jobs')
2029
+
2030
+ # Schedule each job with the job manager
2031
+ for job in jobs:
2032
+ try:
2033
+ if job.job_type == GenericJob.JobType.CANCEL_PIPELINE_RUN:
2034
+ pipeline_run_id = job.payload.get('pipeline_run_id')
2035
+ cancelled_block_run_ids = job.payload.get('cancelled_block_run_ids')
2036
+ try:
2037
+ kill_cancelled_runs(pipeline_run_id, cancelled_block_run_ids)
2038
+ except Exception:
2039
+ pass
2040
+ # Add job to job manager for execution
2041
+ job_manager.add_job(
2042
+ JobType.GENERIC_JOB,
2043
+ job.id,
2044
+ on_pipeline_run_cancelled,
2045
+ # args
2046
+ job.id,
2047
+ pipeline_run_id,
2048
+ cancelled_block_run_ids,
2049
+ )
2050
+ job.mark_queued()
2051
+ logger.info(f'Scheduled generic job {job.id} ({job.job_type})')
2052
+ else:
2053
+ raise ValueError(f"Unknown job type: {job.job_type}")
2054
+ except Exception as e:
2055
+ error_message = f"Failed to schedule generic job: {str(e)}"
2056
+ logger.exception(f'Failed to schedule generic job {job.id}: {error_message}')
2057
+ job.mark_failed({'error': error_message})
2058
+ except Exception as e:
2059
+ logger.exception(f'Failed to schedule generic jobs: {e}')
@@ -1,4 +1,3 @@
1
- import asyncio
2
1
  import collections
3
2
  import os
4
3
  import traceback
@@ -262,7 +261,7 @@ class PipelineScheduler:
262
261
  pipeline_run=self.pipeline_run,
263
262
  )
264
263
 
265
- asyncio.run(UsageStatisticLogger().pipeline_run_ended(self.pipeline_run))
264
+ UsageStatisticLogger().pipeline_run_ended_sync(self.pipeline_run)
266
265
 
267
266
  self.logger_manager.output_logs_to_destination()
268
267
 
@@ -338,7 +337,7 @@ class PipelineScheduler:
338
337
 
339
338
  @safe_db_query
340
339
  def on_pipeline_run_failure(self, error: str) -> None:
341
- asyncio.run(UsageStatisticLogger().pipeline_run_ended(self.pipeline_run))
340
+ UsageStatisticLogger().pipeline_run_ended_sync(self.pipeline_run)
342
341
  self.notification_sender.send_pipeline_run_failure_message(
343
342
  pipeline=self.pipeline,
344
343
  pipeline_run=self.pipeline_run,
@@ -1317,7 +1316,7 @@ def stop_pipeline_run(
1317
1316
  # Update pipeline run status to cancelled
1318
1317
  pipeline_run.update(status=status)
1319
1318
 
1320
- asyncio.run(UsageStatisticLogger().pipeline_run_ended(pipeline_run))
1319
+ UsageStatisticLogger().pipeline_run_ended_sync(pipeline_run)
1321
1320
 
1322
1321
  # Cancel all the block runs
1323
1322
  cancel_block_runs_and_jobs(pipeline_run, pipeline)
@@ -1568,7 +1567,7 @@ def schedule_all():
1568
1567
  concurrency_config = ConcurrencyConfig.load(config=pipeline.concurrency_config)
1569
1568
 
1570
1569
  lock_key = f'pipeline_schedule_{pipeline_schedule.id}'
1571
- if not lock.try_acquire_lock(lock_key):
1570
+ if not lock.try_acquire_lock(lock_key, timeout=30):
1572
1571
  continue
1573
1572
 
1574
1573
  try:
@@ -1,8 +1,11 @@
1
+ import traceback
1
2
  from dataclasses import dataclass
2
3
 
3
4
  from mage_ai.shared.config import BaseConfig
4
5
  from mage_ai.shared.enum import StrEnum
5
6
 
7
+ DEFAULT_CONCURRENCY = 20
8
+
6
9
 
7
10
  class QueueType(StrEnum):
8
11
  CELERY = 'celery'
@@ -17,5 +20,12 @@ class ProcessQueueConfig(BaseConfig):
17
20
  @dataclass
18
21
  class QueueConfig(BaseConfig):
19
22
  queue_type: QueueType = QueueType.PROCESS
20
- concurrency: int = 20
23
+ concurrency: int = DEFAULT_CONCURRENCY
21
24
  process_queue_config: ProcessQueueConfig = None
25
+
26
+ def __post_init__(self):
27
+ try:
28
+ self.concurrency = int(self.concurrency)
29
+ except Exception:
30
+ traceback.print_exc()
31
+ self.concurrency = DEFAULT_CONCURRENCY
@@ -19,6 +19,7 @@ from mage_ai.settings import (
19
19
  HOSTNAME,
20
20
  REDIS_URL,
21
21
  SENTRY_DSN,
22
+ SENTRY_SERVER_NAME,
22
23
  SENTRY_TRACES_SAMPLE_RATE,
23
24
  SERVER_LOGGING_FORMAT,
24
25
  SERVER_VERBOSITY,
@@ -287,6 +288,7 @@ class Worker(mp.Process):
287
288
  sentry_sdk.init(
288
289
  self.dsn,
289
290
  traces_sample_rate=SENTRY_TRACES_SAMPLE_RATE,
291
+ server_name=SENTRY_SERVER_NAME,
290
292
  )
291
293
  initialize_new_relic()
292
294
 
@@ -1,12 +1,19 @@
1
+ import os
2
+
1
3
  from mage_ai.services.redis.redis import init_redis_client
2
4
  from mage_ai.settings import REDIS_URL
3
5
 
6
+ try:
7
+ REDIS_LOCK_DEFAULT_TIMEOUT = int(os.getenv('REDIS_LOCK_DEFAULT_TIMEOUT', 30) or 30)
8
+ except Exception:
9
+ REDIS_LOCK_DEFAULT_TIMEOUT = 30
10
+
4
11
 
5
12
  class DistributedLock:
6
13
  def __init__(
7
14
  self,
8
15
  lock_key_prefix='LOCK_KEY',
9
- lock_timeout=30,
16
+ lock_timeout=REDIS_LOCK_DEFAULT_TIMEOUT,
10
17
  ):
11
18
  self.lock_key_prefix = lock_key_prefix
12
19
  self.lock_timeout = lock_timeout
@@ -1,12 +1,15 @@
1
1
  import asyncio
2
2
  import json
3
+ import re
3
4
  import traceback
5
+ import urllib.parse
4
6
 
5
7
  import dateutil.parser
6
8
  import simplejson
7
9
  import tornado.web
8
10
 
9
11
  from mage_ai.api.middleware import OAuthMiddleware
12
+ from mage_ai.server.api.constants import PATH_TRAVERSAL_PATTERN
10
13
  from mage_ai.shared.parsers import encode_complex
11
14
  from mage_ai.shared.strings import camel_to_snake_case
12
15
  from mage_ai.usage_statistics.constants import EventNameType
@@ -127,11 +130,49 @@ class BaseApiHandler(BaseHandler, OAuthMiddleware):
127
130
  super().initialize(**kwargs)
128
131
  self.is_health_check = kwargs.get('is_health_check', False)
129
132
 
133
+ def is_safe_path(self, user_input):
134
+ """
135
+ Check if the user input is safe and doesn't contain path traversal sequences.
136
+ """
137
+ return re.match(PATH_TRAVERSAL_PATTERN, user_input) is not None
138
+
130
139
  def prepare(self):
131
140
  from mage_ai.server.server import latest_user_activity
132
141
 
133
142
  if not self.is_health_check:
134
143
  latest_user_activity.update_latest_activity()
144
+
145
+ # Validate the request path by decoding from bytes to string if necessary
146
+ decoded_path = self.request.path
147
+ if isinstance(decoded_path, bytes):
148
+ decoded_path = decoded_path.decode('utf-8') # Decode only if it's a bytes object
149
+
150
+ decoded_path = urllib.parse.unquote(decoded_path) # Decode URL-encoded characters
151
+ if not self.is_safe_path(decoded_path):
152
+ self.set_status(400) # Bad Request
153
+ self.write("Error: Invalid path (path traversal detected)")
154
+ self.finish()
155
+ return
156
+
157
+ # Validate query parameters (if any)
158
+ for key, value in self.request.arguments.items():
159
+ # Decode each key and value from bytes to string if necessary
160
+ decoded_key = key
161
+ if isinstance(decoded_key, bytes):
162
+ decoded_key = decoded_key.decode('utf-8')
163
+
164
+ decoded_value = value[0]
165
+ if isinstance(decoded_value, bytes):
166
+ decoded_value = decoded_value.decode('utf-8')
167
+
168
+ decoded_value = urllib.parse.unquote(decoded_value) # Decode URL-encoded characters
169
+ if not self.is_safe_path(decoded_value):
170
+ self.set_status(400)
171
+ self.write(
172
+ f"Error: Invalid parameter value for '{decoded_key}' (path traversal detected)"
173
+ )
174
+ self.finish()
175
+ return
135
176
  super().prepare()
136
177
 
137
178
 
@@ -3,4 +3,5 @@ ENDPOINTS_BYPASS_OAUTH_CHECK = []
3
3
  HEADER_API_KEY = 'X-API-KEY'
4
4
  HEADER_OAUTH_TOKEN = 'OAUTH-TOKEN'
5
5
  OAUTH_CLIENT_ID_KEY = 'OAUTH_CLIENT_ID'
6
+ PATH_TRAVERSAL_PATTERN = r"^(?!.*(\.\.\/|\.\.\\)).*$"
6
7
  URL_PARAMETER_API_KEY = 'api_key'
@@ -23,6 +23,15 @@ class ApiTriggerPipelineHandler(BaseHandler):
23
23
  if token is None:
24
24
  token = get_bearer_auth_token_from_headers(self.request.headers)
25
25
 
26
+ if ScheduleType.API != pipeline_schedule.schedule_type:
27
+ raise UnauthenticatedRequestException(
28
+ 'This endpoint is only supported for API trigger.',
29
+ )
30
+ if not pipeline_schedule.token:
31
+ raise UnauthenticatedRequestException(
32
+ 'The token of the API trigger cannot be empty.',
33
+ )
34
+
26
35
  if ScheduleType.API == pipeline_schedule.schedule_type and \
27
36
  pipeline_schedule.token and \
28
37
  pipeline_schedule.token != token:
@@ -12,4 +12,4 @@ DATAFRAME_OUTPUT_SAMPLE_COUNT = 10
12
12
  # Dockerfile depends on it because it runs ./scripts/install_mage.sh and uses
13
13
  # the last line to determine the version to install.
14
14
  VERSION = \
15
- '0.9.75'
15
+ '0.9.77'
@@ -27,7 +27,7 @@
27
27
  };
28
28
  }
29
29
  })();
30
- </script><link rel="preload" href="/_next/static/css/18782af6d2c4e826.css" as="style"/><link rel="stylesheet" href="/_next/static/css/18782af6d2c4e826.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-0bc44da590c7cf85.js" defer=""></script><script src="/_next/static/chunks/framework-ea07653270784974.js" defer=""></script><script src="/_next/static/chunks/main-f39b6301263551db.js" defer=""></script><script src="/_next/static/chunks/pages/_app-13bf3b7dcef50c29.js" defer=""></script><script src="/_next/static/chunks/pages/404-8ecd93274c427b76.js" defer=""></script><script src="/_next/static/38-PtskJFUTYUpRhT1qF_/_buildManifest.js" defer=""></script><script src="/_next/static/38-PtskJFUTYUpRhT1qF_/_ssgManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.11">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
30
+ </script><link rel="preload" href="/_next/static/css/18782af6d2c4e826.css" as="style"/><link rel="stylesheet" href="/_next/static/css/18782af6d2c4e826.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-b9a067f3bd0a3a05.js" defer=""></script><script src="/_next/static/chunks/framework-ea07653270784974.js" defer=""></script><script src="/_next/static/chunks/main-f39b6301263551db.js" defer=""></script><script src="/_next/static/chunks/pages/_app-782dd4a6b13e1c42.js" defer=""></script><script src="/_next/static/chunks/pages/404-8ecd93274c427b76.js" defer=""></script><script src="/_next/static/qR0jauUABqPaFMjUsYeoG/_buildManifest.js" defer=""></script><script src="/_next/static/qR0jauUABqPaFMjUsYeoG/_ssgManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.11">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
31
31
  *,*::before,*::after{-webkit-box-sizing:inherit;box-sizing:inherit;}/*!sc*/
32
32
  data-styled.g4[id="sc-global-czSCUT1"]{content:"sc-global-czSCUT1,"}/*!sc*/
33
33
  .cGTklP{margin-top:16px;margin-bottom:16px;}/*!sc*/
@@ -46,4 +46,4 @@ data-styled.g81[id="Headline__H1Style-sc-12jzt2e-2"]{content:"wrkfv,"}/*!sc*/
46
46
  .dionUf .Toastify__toast--success{background:#00A81A !important;color:#FFFFFF !important;}/*!sc*/
47
47
  .dionUf .Toastify__toast--warning{background:#DD9900 !important;color:#FFFFFF !important;}/*!sc*/
48
48
  data-styled.g279[id="ToastWrapper-sc-1a33ph1-0"]{content:"dionUf,"}/*!sc*/
49
- </style></head><body><div id="__next"><div class="" style="position:fixed;top:0;left:0;height:2px;background:transparent;z-index:99999999999;width:100%"><div class="" style="height:100%;background:#FF144D;transition:all 500ms ease;width:0%"><div style="box-shadow:0 0 10px #FF144D, 0 0 10px #FF144D;width:5%;opacity:1;position:absolute;height:100%;transition:all 500ms ease;transform:rotate(3deg) translate(0px, -4px);left:-10rem"></div></div></div><main style="align-items:center;display:flex;flex-direction:column;height:100vh;margin-top:16rem"><svg width="84.70857142857143" height="64" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path opacity="0.4" d="M15.3266 0L19.2641 1.82961e-06L11.9687 14L8.03125 14L15.3266 0Z" fill="url(#paint0_linear_1303_5)"></path><path d="M11.9692 1.82961e-06L8.03164 0L0.736328 14L4.67383 14L8.03164 7.55626V14H11.9691V8.38194e-05L11.9692 1.82961e-06Z" fill="url(#paint1_linear_1303_5)"></path><path d="M15.3269 2.57679e-06H19.2644V14H15.3269V2.57679e-06Z" fill="url(#paint2_linear_1303_5)"></path><defs><linearGradient id="paint0_linear_1303_5" x1="8.03125" y1="7" x2="19.2641" y2="7" gradientUnits="userSpaceOnUse"><stop offset="0.28125" stop-color="#7D55EC"></stop><stop offset="1" stop-color="#2AB2FE"></stop></linearGradient><linearGradient id="paint1_linear_1303_5" x1="0.736328" y1="7" x2="19.2644" y2="7" gradientUnits="userSpaceOnUse"><stop offset="0.28125" stop-color="#7D55EC"></stop><stop offset="1" stop-color="#2AB2FE"></stop></linearGradient><linearGradient id="paint2_linear_1303_5" x1="0.736328" y1="7" x2="19.2644" y2="7" gradientUnits="userSpaceOnUse"><stop offset="0.28125" stop-color="#7D55EC"></stop><stop offset="1" stop-color="#2AB2FE"></stop></linearGradient></defs></svg><div class="Spacing__SpacingStyle-sc-1mpmtgj-0 cGTklP"><div class="Headline__HeadlineContainerStyle-sc-12jzt2e-0 hxvzgz"><h1 class="Headline__H1Style-sc-12jzt2e-2 wrkfv">404 - Page Not Found<!-- --></h1></div></div><p class="Text__TextStyle-sc-sl5nur-0 cKjmRF">You will be redirected to the Pipelines dashboard in <!-- -->5<!-- --> seconds.<!-- --></p></main><div id="command-center-root"></div><div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 dionUf"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanLight":"rgba(101, 227, 255, 0.3)","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtDark":"rgba(252, 105, 73, 0.3)","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"rgb(255, 79, 248, 0.5)","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","rose":"#D1A2AB","roseLight":"rgba(209, 162, 171, 0.5)","sky":"#6AA1E0","skyLight":"rgba(106, 161, 224, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"blackTransparent":"rgba(0, 0, 0, 0.6)","blackTransparentDark":"rgba(0, 0, 0, 0.8)","chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","dashboard":"#18181C","dashboardTransparent":"rgba(24, 24, 28, 0.1)","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","panelTransparent":"rgba(35, 36, 41, 0.7)","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","successLight":"rgb(138, 222, 0, 0.3)","table":"#292A2F","tag":"#3A4550"},"borders":{"button":"#454850","contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","darkLight":"#2E3036","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","medium2":"#141414","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","blackBackgroundTransparent":"rgba(0, 0, 0, 0.5)","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBackgroundTransparent":"rgba(54, 56, 63, 0.5)","defaultBorder":"#ffffff1a","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBackgroundTransparent":"rgba(78, 78, 78, 0.5)","hoverBlackBackgroundTransparent":"rgba(0, 0, 0, 0.7)","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkPrimaryLight":"#5982ff","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","linkText":"#6AA1E0","linkTextLight":"#9ECBFF","purple":"#885EFF","rowHoverBackground":"rgba(0, 0, 0, 0.1)","transparent":"rgba(255, 255, 255, 0)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF","whiteTransparent":"rgba(255, 255, 255, 0.6)"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(0, 0, 0, 0.3)","frame":"0px 10px 40px rgba(0, 0, 0, 0.26)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/404","query":{},"buildId":"38-PtskJFUTYUpRhT1qF_","nextExport":true,"isFallback":false,"appGip":true,"scriptLoader":[]}</script></body></html>
49
+ </style></head><body><div id="__next"><div class="" style="position:fixed;top:0;left:0;height:2px;background:transparent;z-index:99999999999;width:100%"><div class="" style="height:100%;background:#FF144D;transition:all 500ms ease;width:0%"><div style="box-shadow:0 0 10px #FF144D, 0 0 10px #FF144D;width:5%;opacity:1;position:absolute;height:100%;transition:all 500ms ease;transform:rotate(3deg) translate(0px, -4px);left:-10rem"></div></div></div><main style="align-items:center;display:flex;flex-direction:column;height:100vh;margin-top:16rem"><svg width="84.70857142857143" height="64" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path opacity="0.4" d="M15.3266 0L19.2641 1.82961e-06L11.9687 14L8.03125 14L15.3266 0Z" fill="url(#paint0_linear_1303_5)"></path><path d="M11.9692 1.82961e-06L8.03164 0L0.736328 14L4.67383 14L8.03164 7.55626V14H11.9691V8.38194e-05L11.9692 1.82961e-06Z" fill="url(#paint1_linear_1303_5)"></path><path d="M15.3269 2.57679e-06H19.2644V14H15.3269V2.57679e-06Z" fill="url(#paint2_linear_1303_5)"></path><defs><linearGradient id="paint0_linear_1303_5" x1="8.03125" y1="7" x2="19.2641" y2="7" gradientUnits="userSpaceOnUse"><stop offset="0.28125" stop-color="#7D55EC"></stop><stop offset="1" stop-color="#2AB2FE"></stop></linearGradient><linearGradient id="paint1_linear_1303_5" x1="0.736328" y1="7" x2="19.2644" y2="7" gradientUnits="userSpaceOnUse"><stop offset="0.28125" stop-color="#7D55EC"></stop><stop offset="1" stop-color="#2AB2FE"></stop></linearGradient><linearGradient id="paint2_linear_1303_5" x1="0.736328" y1="7" x2="19.2644" y2="7" gradientUnits="userSpaceOnUse"><stop offset="0.28125" stop-color="#7D55EC"></stop><stop offset="1" stop-color="#2AB2FE"></stop></linearGradient></defs></svg><div class="Spacing__SpacingStyle-sc-1mpmtgj-0 cGTklP"><div class="Headline__HeadlineContainerStyle-sc-12jzt2e-0 hxvzgz"><h1 class="Headline__H1Style-sc-12jzt2e-2 wrkfv">404 - Page Not Found<!-- --></h1></div></div><p class="Text__TextStyle-sc-sl5nur-0 cKjmRF">You will be redirected to the Pipelines dashboard in <!-- -->5<!-- --> seconds.<!-- --></p></main><div id="command-center-root"></div><div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 dionUf"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanLight":"rgba(101, 227, 255, 0.3)","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtDark":"rgba(252, 105, 73, 0.3)","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"rgb(255, 79, 248, 0.5)","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","rose":"#D1A2AB","roseLight":"rgba(209, 162, 171, 0.5)","sky":"#6AA1E0","skyLight":"rgba(106, 161, 224, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"blackTransparent":"rgba(0, 0, 0, 0.6)","blackTransparentDark":"rgba(0, 0, 0, 0.8)","chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","dashboard":"#18181C","dashboardTransparent":"rgba(24, 24, 28, 0.1)","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","panelTransparent":"rgba(35, 36, 41, 0.7)","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","successLight":"rgb(138, 222, 0, 0.3)","table":"#292A2F","tag":"#3A4550"},"borders":{"button":"#454850","contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","darkLight":"#2E3036","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","medium2":"#141414","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","blackBackgroundTransparent":"rgba(0, 0, 0, 0.5)","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBackgroundTransparent":"rgba(54, 56, 63, 0.5)","defaultBorder":"#ffffff1a","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBackgroundTransparent":"rgba(78, 78, 78, 0.5)","hoverBlackBackgroundTransparent":"rgba(0, 0, 0, 0.7)","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkPrimaryLight":"#5982ff","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","linkText":"#6AA1E0","linkTextLight":"#9ECBFF","purple":"#885EFF","rowHoverBackground":"rgba(0, 0, 0, 0.1)","transparent":"rgba(255, 255, 255, 0)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF","whiteTransparent":"rgba(255, 255, 255, 0.6)"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(0, 0, 0, 0.3)","frame":"0px 10px 40px rgba(0, 0, 0, 0.26)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/404","query":{},"buildId":"qR0jauUABqPaFMjUsYeoG","nextExport":true,"isFallback":false,"appGip":true,"scriptLoader":[]}</script></body></html>