3 months ago
Hello everyone,
I'm making a simple React app which eventually will become two Docker containers: one for my app, the other for my API.
I tried to implement the Railway API to my CI/CD pipeline, basically, what I wanted to do :
My changed are pushed to/merged onto 'main' branch
Github Actions runs some tests
Then, it runs a Python script which executes steps 4-6
Two containers are built from my project and pushed to Docker Hub with a specific tag
The script sends a mutation request for the 'serviceInstanceUpdate()' method
The scripts sends another mutation request for the 'serviceInstanceRedeploy()' method
My two services are updated and running with the correct container image
Keep in mind that I'm very new using this kind of automated pipeline, and I never touched GraphQL before. I tried my best with the Railway sandbox, using the same mutation with the same variables and header, but to no avail.
If that might help, here's the python script:
import os, requests, datetime, subprocess
DOCKER_USER = "username"
API_NAME = "xxx-api"
APP_NAME = "xxx-app"
RAILWAY_API_URL = "https://backboard.railway.com/graphql/v2"
RAILWAY_TOKEN = os.environ.get("RAILWAY_TOKEN")
RAILWAY_API_SERVICE_ID = os.environ.get("RAILWAY_API_SERVICE_ID")
RAILWAY_API_ENV_ID = os.environ.get("RAILWAY_API_ENV_ID")
RAILWAY_APP_SERVICE_ID = os.environ.get("RAILWAY_APP_SERVICE_ID")
RAILWAY_APP_ENV_ID = os.environ.get("RAILWAY_APP_ENV_ID")
TAG = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
def run(cmd):
print(f"$ {cmd}")
subprocess.run(cmd, shell=True, check=True)
def docker_build_and_push(name, path):
image = f"{DOCKER_USER}/{name}:{TAG}"
run(f"docker build -t {image} {path}")
run(f"docker push {image}")
return image
def railway_update(service_id, env_id, image):
mutation = """
mutation serviceInstanceUpdate($environmentId: String!, $input: ServiceInstanceUpdateInput!, $serviceId: $String!) {
serviceInstanceUpdate(environmentId: $id, input: $input, serviceId: $serviceId) {
environmentId
input
serviceId
}
}
"""
variables = {
"environmentId": env_id,
"serviceId": service_id,
"input": {
"source": {
"image": image
}
}
}
headers = {
"Authorization": f"Bearer {RAILWAY_TOKEN}",
"Content-Type": "application/json"
}
req = requests.post(
RAILWAY_API_URL,
json={ "query": mutation, "variables": variables },
headers=headers
)
req.raise_for_status()
print("Railway update response:", req.json())
def main():
print("[1/3] Building and pushing API...")
api_image = docker_build_and_push(API_NAME, "./api")
print("[2/3] Building and pushing app...")
app_image = docker_build_and_push(APP_NAME, "./")
print("[3/3] Updating Railway services...")
railway_update(RAILWAY_API_SERVICE_ID, RAILWAY_API_ENV_ID, api_image)
railway_update(RAILWAY_APP_SERVICE_ID, RAILWAY_APP_ENV_ID, app_image)
print("🚀 Deployment successful with tag:", TAG)
if __name__ == "__main__":
main()The closest hint I can get is from the Github Actions' error message, telling me that it returned an error code 400, which might mean I didn't properly write the request.
I'm very thankful for your help, it's been bothering me for a while, and this is pretty time-sensitive. And, apologies for my bad english.
Attachments
2 Replies
3 months ago
Hey there! We've found the following might help you get unblocked faster:
If you find the answer from one of these, please let us know by solving the thread!
3 months ago
Oh, by the way, I forgot the "serviceInstanceRedeploy" method in python
def railway_redeploy(env_id, service_id):
mutation = """
mutation serviceInstanceRedeploy($environmentId: String!, $serviceId: $String!) {
serviceInstanceRedeploy(environmentId: $id, serviceId: $serviceId) {
environmentId
input
serviceId
}
}
"""
variables = {
"environmentId": env_id,
"serviceId": service_id
}
headers = {
"Authorization": f"Bearer {RAILWAY_TOKEN}",
"Content-Type": "application/json"
}
req = requests.post(
RAILWAY_API_URL,
json={ "query": mutation, "variables": variables },
headers=headers
)
req.raise_for_status()
print("Railway update response:", req.json())