Are there any example apps for deployment that cov...
# help
d
Are there any example apps for deployment that cover both DEV and PROD? I can only ever run
npx sst depoy --stage prod
once. After than I get barrels of cloud formation errors.
g
We would need to know what the actual error you get is to help because everything should just work whenever you update and redeploy.
d
For sure. And I’m happy to provide those, but also want to respect folks time rather than be like “debug this for me” 😅
in this case I get
Copy code
prod-hallofabandonedideas-ideasStack failed: prod-hallofabandonedideas-Ideas already exists
and errors that look like
Copy code
prod-yourdomain-ideasStack | CREATE_FAILED | AWS::DynamoDB::Table | IdeasTable5FC50FD8 prod-yourdomain-Ideas already exists
essentially, my app is a next app that follows the existing next tutorial + the tutorial
g
It looks like from that 2nd error at least its trying to create a table but it already exists which means either your construct id for the table is changing or you removed the stack but had it retain resources such as dynamo so when you try to create the stack again the table will already exist - no idea what the first one is about never seen that before.
d
Yep. It is trying to deploy the same table again, even though I didn’t change anything about the table
Which I’m pretty sure means that I’ve set the table contruct up in some way that is incorrect. thus the desire to see what a prod example might look like.
g
The table's between dev & prod should just be setup exactly the same, I only change 2 options but they would not affect deployment if I did not change them based on dev vs prod... This is my helper function for building the dynamo table though:
Copy code
import * as sst from '@serverless-stack/resources'
import * as cdk from '@aws-cdk/core'
import * as dynamo from '@aws-cdk/aws-dynamodb'

const getFieldsAndIndexes = (input: [number, number, sst.TableFieldType][]) => {
	const output: {
		primaryIndex: sst.TableIndexProps
		globalIndexes: Record<string, sst.TableGlobalIndexProps>
		fields: Record<string, sst.TableFieldType>
	} = {
		primaryIndex: {
			partitionKey: 'pk',
			sortKey: 'sk'
		},
		fields: {
			pk: sst.TableFieldType.STRING,
			sk: sst.TableFieldType.STRING
		},
		globalIndexes: {}
	}

	for (const [start, end, fieldType] of input)
		for (let i = start; i <= end; i++) {
			output.globalIndexes[`gsi${i}`] = {
				partitionKey: `gsi${i}pk`,
				sortKey: `gsi${i}sk`
			}
			output.fields[`gsi${i}pk`] = sst.TableFieldType.STRING
			output.fields[`gsi${i}sk`] = fieldType
		}

	return output
}

export default function createTable (scope: sst.Stack, fieldsAndIndexes: [number, number, sst.TableFieldType][] = []) {
	return new sst.Table(scope, 'Table', {
		...getFieldsAndIndexes(fieldsAndIndexes),
		stream: true,
		dynamodbTable: {
			billingMode: dynamo.BillingMode.PAY_PER_REQUEST,
			pointInTimeRecovery: scope.stage === 'production',
			timeToLiveAttribute: 'ttl',
			removalPolicy: scope.stage === 'production' ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY
		}
	})
}
As you can see though only difference from dev vs prod is pitr & removalPolicy and those dont affect deploys in any way so if what you have works for dev I would assume you change something on prod that you shouldnt would need to see code though
d
Hmm mine looks pretty similar. I don’t have anything about setting billing mode or streams. Since the table is basically a hit counter right now.
Last time I had to manually delete a bunch of resources in AWS, which I’m going to try again. But obvs this isn’t sustainable. I’ll try again and maybe something will reveal itself.
Copy code
// Create the DynamoDB table
    this.table = new sst.Table(this, "Ideas", {
      fields: {
        count: sst.TableFieldType.STRING,
      },
      primaryIndex: { partitionKey: "pk", sortKey: "sk" },
    });
that’s what the table looks like. So there’s nothing there that seems like it should be wrong
g
I'm not sure how that table would work at all for you. You have to define the fields that are used in your primary index. So:
Copy code
// Create the DynamoDB table
    this.table = new sst.Table(this, "Ideas", {
      fields: {
        pk: sst.TableFieldType.STRING,
        sk: sst.TableFieldType.STRING,
        count: sst.TableFieldType.STRING,
      },
      primaryIndex: { partitionKey: "pk", sortKey: "sk" },
    });
d
Hmm. I wonder if not doing that and just trying to get to the simplest possible deploy was why it couldn’t realize they are the same table
This time I ran,
npx sst deploy --stage prod
and got a failure around route53 So I went in and manually removed all records for that. And then when i tried again presto the table error is back
f
@Devin when u remove the app, resources like DynamoDB tables, S3 buckets don’t get removed by default.
d
Yes that part I understand
But how do I deploy a second time
f
For non-prod stages, ppl often set the removal policy to REMOVE, so the tables and buckets are also removed.
If you are trying to repetitively deploy/teardown, set this flag as well.
Let me know if that makes sense.
d
Ya for sure. I’ve been there. Let me ask in a different way.
Copy code
I built an app that has a bucket, a table, auth, next to a custom domain. It works locally. The next app renders... Hello World

I deploy the app using sst deploy stage --prod

I decide to change the next app to say

Hello Frank
I cannot deploy because of a variety of errors. Different each time.
Usually it’s the table. But also I’ve seen A record issues etc…
f
Oh… 🤯
it seems CFN is trying recreate the table… weird
d
Yeah. And I assume it’s me because I have no idea what I’m doing.
f
Try this: • go to ur CFN console and get the CFN template for this stack that’s being used on live • run
sst build
locally and go into
.build/cdk.out
and look up the newly generated template Diff the two templates and see what changed.
d
k
f
I often use this to share the diff https://www.diffchecker.com
Feel free to share it here
d
will do. This will probably take a while because I’ve manually deleted so much that things are kinda whacky and out of sync