Comments (3)
Thank you for letting us know about this. I've let our product team know, we'll decide how we want to handle this issue.
from heroku-cli.
This our workaround, we are a python application.
import os
from time import sleep
import httpx
class HerokuClient:
def __init__(self, app: str | None = None, api_key: str | None = None) -> None:
self.heroku_app = app or os.environ["HEROKU_APP"]
self.api_key = api_key or os.environ["HEROKU_API_KEY"]
self.client = httpx.Client(
base_url=f"https://api.heroku.com/apps/{self.heroku_app}",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}",
},
)
def retrieve_last_release(self):
previous_release = self.client.get(
"/releases",
headers={
"Accept": "application/vnd.heroku+json; version=3",
"Range": "version ..; max=2, order=desc",
},
)
previous_release.raise_for_status()
return previous_release.json()[0]
def release(self, processes: list[str]):
# Retrieve the previous release
last_release = self.retrieve_last_release()
# Trigger the release
print(f"🚀 releasing {', '.join(processes)}") # noqa: T201)
self.client.patch(
"/formation",
json={
"updates": [
{"type": target, "docker_image": self.latest_image_digest(target=target)}
for target in processes
]
},
headers={"Accept": "application/vnd.heroku+json; version=3.docker-releases"},
)
# Retrieve the new release
# We give Heroku a tiny bit of time between triggering the formation update and retrieving the current release
# to mitigate any race conditions between their microservices.
sleep(10)
current_release = self.retrieve_last_release()
# Ensure the release was actually created
if (not last_release and not current_release) or (
last_release and last_release["id"] == current_release["id"]
):
print("❌ failed to release - new release was not created") # noqa: T201
exit(1)
return current_release
def stream(self, url: str, retries=30):
range_header = {}
streamed_bytes = 0
print(f"attemping stream {url}") # noqa: T201
while True:
try:
with httpx.stream("GET", url, headers=range_header) as stream:
stream.raise_for_status()
for chunk in stream.iter_text():
print(chunk, end="") # noqa: T201
streamed_bytes += len(chunk)
break
except httpx.HTTPError as e:
if retries > 0:
retries -= 1
range_header["Range"] = f"bytes={streamed_bytes}"
if streamed_bytes > 0:
sleep(4)
else:
sleep(8)
else:
raise e
def latest_image_digest(self, target: str):
manifest_request = self.client.get(
f"https://registry.heroku.com/v2/{self.heroku_app}/{target}/manifests/latest",
auth=httpx.BasicAuth("_", self.api_key),
headers={
"Accept": "application/vnd.docker.distribution.manifest.v2+json",
},
)
manifest_request.raise_for_status()
return manifest_request.json()["config"]["digest"]
def ensure_successful_release(self, retries=10):
max_sleep = 8 # Maximum sleep time in seconds
attempt = 0 # Current attempt number
while True:
try:
current_release = self.retrieve_last_release()
if current_release["status"] == "failed" or retries <= 0:
print( # noqa: T201
f"❌ failed to release / status={current_release['status']} / https://dashboard.heroku.com/apps/{self.heroku_app}"
)
exit(1)
elif current_release["status"] == "succeeded":
print("✅ successfully released") # noqa: T201
return
except Exception: # noqa: S110
pass
sleep_time = min(2**attempt, max_sleep)
sleep(sleep_time)
attempt += 1
retries -= 1
if __name__ == "__main__":
client = HerokuClient()
# Trigger the release
current_release = client.release(processes=PROCESSES)
# Stream the output
if current_release["status"] == "pending" and current_release["output_stream_url"]:
print( # noqa: T201
"🪵 the current release is pending -- attempting to stream release logs..."
)
print("===============================================\n\n") # noqa: T201
try:
client.stream(current_release["output_stream_url"])
except Exception:
print("❌ streaming release output failed; release is ongoing...") # noqa: T201
print("\n\n===============================================\n\n") # noqa: T201
else:
print( # noqa: T201
f"🤔 the current release is {current_release['status']} with output stream url {current_release['output_stream_url']} -- skipping log streaming..."
)
# Ensure the release phase completed successfully
client.ensure_successful_release()
from heroku-cli.
In terms of impact, we see about 5-10% failure rate on deploys using the CLI implementation.
from heroku-cli.
Related Issues (20)
- plugin-mtls is not installing using heroku cli HOT 4
- Heroku login -- unable to verify the first certificate HOT 12
- Release Key Expired? HOT 13
- Broken autocomplete when installing CLI with homebrew on Linux HOT 4
- Syntax coloration is disabled HOT 7
- node 16 EOL ended 7 months and 3 weeks ago HOT 4
- `heroku commands --json` yields MODULE_NOT_FOUND HOT 1
- i have an issue with heroku login HOT 1
- ERR_UNESCAPED_CHARACTERS: Request path contains unescaped characters HOT 1
- Windows - Add `DisplayVersion` key to registry HOT 6
- Windows - Add DisplayVersion key to registry HOT 1
- Breaking Change for `heroku container:push --recursive` on 9.0.0 HOT 1
- heroku container:release no longer allows migration from heroku-xx stacks since 9.0.0 HOT 2
- CLI v9: breaking regression for pg:backups:schedule when passing in timezone HOT 2
- `heroku run` command arguments are incorrectly sorted, breaking command functionality HOT 11
- heroku/cli docker image not found HOT 1
- Broken build while using older version of docker HOT 1
- <!--
- Heroku/CLI
- Cli
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from heroku-cli.