Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); AIRFLOW-3149 Support dataproc cluster deletion on ERROR by dossett · Pull Request #4064 · apache/airflow · GitHub
Skip to content

AIRFLOW-3149 Support dataproc cluster deletion on ERROR - #4064

Merged
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149
Sep 17, 2019
Merged

AIRFLOW-3149 Support dataproc cluster deletion on ERROR#4064
mik-laj merged 12 commits into
apache:masterfrom
dossett:AIRFLOW-3149

Conversation

@dossett

@dossettdossett commented Oct 17, 2018

Copy link
Copy Markdown
Contributor

Sometimes a dataproc cluster creation results in a
cluster in a state of ERROR, which makes it unsuable.
Subsequent Airflow retries will fail because a cluster
already exists. This change adds the option to delete
an ERROR cluster on creation so that subsequent attempts
might succeed. There are also some other small cleanups.

Make sure you have checked all steps below.

Jira

  • My PR addresses the following Airflow Jira issues and references them in the PR title.

Description

  • See commit message above

Tests

  • My PR adds the following unit tests OR does not need testing for this extremely good reason:

My change does not include tests, I did not see any integration tests in the code base that this could fit into.

Commits

  • My commits all reference Jira issues in their subject lines, and I have squashed multiple commits if they address the same issue. In addition, my commits follow the guidelines from "How to write a good git commit message":
    1. Subject is separated from body by a blank line
    2. Subject is limited to 50 characters (not including Jira issue reference)
    3. Subject does not end with a period
    4. Subject uses the imperative mood ("add", not "adding")
    5. Body wraps at 72 characters
    6. Body explains "what" and "why", not "how"

Documentation

  • In case of new functionality, my PR adds documentation that describes how to use it.
    • When adding new operators/hooks/sensors, the autoclass documentation generation needs to be added.

Code Quality

  • Passes flake8

@fenglu-db

Copy link
Copy Markdown
Contributor

Instead of adding the delete_on_error into the dataproc cluster create operator, curious why you can't have a downstream delete cluster operator with a trigger_rule = upstream failed? Would rather keep the operator logic atomic and simple.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thanks for your comment. My goal wasn't just to make sure the ERROR cluster gets deleted but to give the cluster creation a chance to succeed with a retry.

The behavior we have observed is this:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • the cluster create operator retries based on our DAG configuration
  • the retries fail because a cluster with the same name already exists in the ERROR state
  • after the the retries are exhausted the DAG proceeds with that step as failed

After applying this patch internally we observe:

  • Sometimes a cluster create fails and the cluster exists in an ERROR state
  • We immediately delete the cluster within the create operator
  • the cluster create operator retries based on our DAG configuration
  • the cluster creation succeeds because whatever led to the initial cluster creation ERROR was a transient problem

It has greatly increased the reliability and stability of our GCP DAGS.

@fenglu-db

Copy link
Copy Markdown
Contributor

Sorry for the late reply.

Thank you @dossett for the detailed explanation. The root cause seems to be that DataprocClusterCreateOperator is not idempotent. Similar to what you have described, how about we re-factor the operator based on the following logic?

  • check existence of dataproc cluster
  • if yes and in "running" state, no-op.
  • else, delete the cluster, and attempt create again.

So we don't have to export this additional delete_cluster_on_error?

@dossett

Copy link
Copy Markdown
ContributorAuthor

Hi @fenglu-g thank you for the follow-up! What about taking both approaches? Deleting a cluster first if it already exists, creating the cluster, and if the creation fails and results in an ERROR state deleting it before exiting. That could be the default behavior without the need to add the new parameter (delete_cluster_on_error). Having the operator clean up after itself and not leave errant resources behind seems like a nice property.

@stale

staleBot commented Dec 25, 2018

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 25, 2018
@kaxilkaxil removed the stale Stale PRs per the .github/workflows/stale.yml policy file label Dec 31, 2018
@kaxil

Copy link
Copy Markdown
Member

@dossett Deleting the existing cluster without prior warnings, wouldn't be a good option. I would rather go the appraoch @fenglu-g mentioned.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @kaxil and @fenglu-g for the feedback. I will work on this when I'm back in the office next week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to put this code in Hook.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @mik-laj - makes sense to move it to Hooks

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kaxil and @mik-laj I missed this the first time. I will make this change.

@dossett
dossettforce-pushed the AIRFLOW-3149 branch 2 times, most recently from 6750b8c to 8aa742cCompareJanuary 25, 2019 16:31
@dossett

Copy link
Copy Markdown
ContributorAuthor

@kaxil @fenglu-g I have redone this PR with the new approach per our discussion. Looking forward to additional feedback!

@dossett

Copy link
Copy Markdown
ContributorAuthor

Moved common code to the hook and cleaned up some flake8 errors

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
).execute()
).execute(num_retries=5)

Google API sometimes does not respond correctly. You should send a request again.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@mik-lajmik-lajFeb 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.log.info('Diagnostic information for ERROR cluster available at ['+
output_url .=diagnose_result.get('response').get('outputUri')
self.log.info('Diagnostic information for ERROR cluster available at [%s]', output_url)

You should avoid formatting the text before passing it to the logger. When text and data are passef to the logger separately, special loggers allow to analyze in a deeper way.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you again @mik-laj, that's a great point. Change pushed.

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Note the flake8 errors:

./airflow/contrib/hooks/gcp_dataproc_hook.py:255:5: E303 too many blank lines (2)
./airflow/contrib/hooks/gcp_dataproc_hook.py:268:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:275:5: E303 too many blank lines (2)
./airflow/contrib/operators/dataproc_operator.py:287:5: E303 too many blank lines (2)

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @OmerJog, fixed!

@dossett

Copy link
Copy Markdown
ContributorAuthor

I seem to have broken the test_cluster_name_log_sub test, so I'll try to figure that out

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett There is still an error:

53) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

Yeah @OmerJog I haven't been able to track that down

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett You have some errors:

20) FAIL: test_cluster_name_log_sub (tests.contrib.operators.test_dataproc_operator.DataprocClusterDeleteOperatorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
tests/contrib/operators/test_dataproc_operator.py line 511 in test_cluster_name_log_sub
dataproc_task.execute(None)
AssertionError: TypeError not raised

@dossett

Copy link
Copy Markdown
ContributorAuthor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

@piffall

piffall commented Apr 17, 2019

Copy link
Copy Markdown
Contributor

@OmerJog I went over that test in detail and it seems like the with self.assertRaises(TypeError) was a defensive measure to catch an exception within the test and not that raising a TypeError was part of the test specification. I've deleted that line to see if the rest of the test is successful.

cc @piffall who added that line about 11 months ago

Hi @dossett, in fact, I didn't add that line, I just keep that test with a minor change.

@codecov-io

codecov-io commented Apr 17, 2019

Copy link
Copy Markdown

Codecov Report

Merging #4064 into master will increase coverage by 0.23%.
The diff coverage is 51.57%.

Impacted file tree graph

@@ Coverage Diff @@## master #4064 +/- ##
==========================================
+ Coverage 78.76% 78.99% +0.23% 
==========================================
Files 481 488 +7 Lines 30215 30642 +427 ==========================================
+ Hits 23800 24207 +407 - Misses 6415 6435 +20
Impacted FilesCoverage Δ
airflow/contrib/operators/dataproc_operator.py79.43% <51.28%> (-4.38%)⬇️
airflow/contrib/hooks/gcp_dataproc_hook.py46.66% <52.94%> (+9.62%)⬆️
airflow/contrib/operators/gcs_download_operator.py78.12% <0%> (-9.88%)⬇️
airflow/api/common/experimental/get_code.py76.92% <0%> (-6.42%)⬇️
...rflow/api/common/experimental/get_task_instance.py84.61% <0%> (-5.39%)⬇️
airflow/api/common/experimental/mark_tasks.py95.2% <0%> (-1.57%)⬇️
airflow/contrib/operators/mlengine_operator.py76.4% <0%> (-0.17%)⬇️
airflow/kubernetes/pod.py100% <0%> (ø)⬆️
airflow/contrib/operators/gcs_list_operator.py100% <0%> (ø)⬆️
airflow/api/common/experimental/get_task.py100% <0%> (ø)⬆️
... and 53 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2fd7567...eaed844. Read the comment docs.

@dossett

Copy link
Copy Markdown
ContributorAuthor

@fenglu-g @kaxil This PR is complete and now passes all tests. We (Etsy) have been running with change locally for a couple of months now and it's been terrific. Clusters in ERROR no longer derail DAGs and automatically retrieving diagnostic information about them has let us diagnose underlying causes with Google support, where before this we couldn't because we had no information.

Thank you @OmerJog and @mik-laj for helpful comments along the way!

@fenglu-dbfenglu-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dossett, mostly LGTM. Two nits and one test case request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/Exception/AirflowException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double check, should the regex pattern be [smdh] as well to be consistent with the get_graceful_decommission_timeout?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly? That would require some other substantive changes right below this line to handle the d and h. My change was just to make the regex a little more standardized, but sometimes those can spill over to more substantive changes. I would want to err on the side of making that a separate change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you also add a test cast that checks that the error cluster is deleted?

@OmerJog

Copy link
Copy Markdown
Contributor

@dossett Can you address the comments and rebase? @kaxil is picking PRs for Airflow 1.10.4 - it would be nice to have this PR in.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Thanks @OmerJog and @fenglu-g ! I've addressed the first two comments, and will rebase and try to add the requested unit test as well. Looking forward to 1.10.4 !

@mik-laj

Copy link
Copy Markdown
Member

Hi.

I made a change in the base class - GoogleCloudBaseHook. Your PR may need to be changed. Could you do rebase?

Thanks

Refenence:
#5907

@potiuk

Copy link
Copy Markdown
Member

Same here @dossett -> we are just moving from contrib to core and we would love to get this one rebased/merged.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Rebase and pushed, awaiting travis

@mik-laj

Copy link
Copy Markdown
Member

Pylint is sad.

@dossett

Copy link
Copy Markdown
ContributorAuthor

Pushed more changes, I'm learning a lot about pylint 😂

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj pylint is happy now, the kubernetes test suite failed but that seems unrelated to my change?

@dossett

Copy link
Copy Markdown
ContributorAuthor

@mik-laj@potiuk All green!

@mik-laj
mik-laj merged commit 578c57f into apache:masterSep 17, 2019
@dossett

Copy link
Copy Markdown
ContributorAuthor

Thank you @mik-laj@potiuk@OmerJog @fenglu-g for all the feedback along the way, it's exciting to see this get merged. Looking forward to making more contributions.

@dossett
dossett deleted the AIRFLOW-3149 branch September 17, 2019 13:18
@mik-laj

Copy link
Copy Markdown
Member

Thank you very much for your cooperation. I am waiting for your next PR. 😸

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider:googleGoogle (including GCP) related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@dossett@fenglu-db@kaxil@OmerJog@piffall@codecov-io@mik-laj@potiuk