Período de vida (TTL) de computación en DynamoDB
Una forma habitual de implementar el TTL consiste en establecer una fecha de vencimiento para los elementos en función de cuándo se crearon o se actualizaron por última vez. Esto se puede hacer añadiendo la hora a las marcas de tiempo createdAt
y updatedAt
. Por ejemplo, el TTL de los elementos que se acaban de crear se puede establecer en createdAt
más 90 días. Cuando se actualiza el elemento, el TTL se puede volver a calcular como updatedAt
más de 90 días.
El tiempo de vencimiento calculado debe estar en formato Epoch, expresado en segundos. Para que se tenga en cuenta el vencimiento y la eliminación, el TTL no puede tener más de cinco años de antigüedad. Si utiliza cualquier otro formato, los procesos de TTL ignoran el elemento. Si establece la fecha de vencimiento en algún momento del futuro en que quiere que caduque el elemento, caducará cuando llegue dicha fecha. Por ejemplo, supongamos que establece la fecha de vencimiento para el 1724241326 (que es el lunes 21 de agosto de 2024 a las 11:55:26 [GMT]). El elemento vencerá cuando se alcance la fecha especificada.
Creación de un elemento y determinación del tiempo de vida
En el siguiente ejemplo se muestra cómo calcular el tiempo de vencimiento al crear un elemento nuevo, utilizando expireAt
como nombre de atributo TTL. Una instrucción de asignación obtiene la hora actual como variable. En el ejemplo, la fecha de vencimiento se calcula en 90 días a partir de la fecha actual. A continuación, la fecha se convierte al formato Epoch y se guarda como un tipo de dato entero en el atributo TTL.
Los siguientes ejemplos de código muestran cómo crear un elemento con TTL.
- Java
-
- SDK para Java 2.x
-
package com.amazon.samplelib.ttl;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.utils.ImmutableMap;
import java.io.Serializable;
import java.util.Map;
import java.util.Optional;
public class CreateTTL {
public static void main(String[] args) {
final String usage = """
Usage:
<tableName> <primaryKey> <sortKey> <region>
Where:
tableName - The Amazon DynamoDB table being queried.
primaryKey - The name of the primary key. Also known as the hash or partition key.
sortKey - The name of the sort key. Also known as the range attribute.
region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
""";
// Optional "region" parameter - if args list length is NOT 3 or 4, short-circuit exit.
if (!(args.length == 3 || args.length == 4)) {
System.out.println(usage);
System.exit(1);
}
String tableName = args[0];
String primaryKey = args[1];
String sortKey = args[2];
Region region = Optional.ofNullable(args[3]).isEmpty() ? Region.US_EAST_1 : Region.of(args[3]);
// Get current time in epoch second format
final long createDate = System.currentTimeMillis() / 1000;
// Calculate expiration time 90 days from now in epoch second format
final long expireDate = createDate + (90 * 24 * 60 * 60);
final ImmutableMap<String, ? extends Serializable> itemMap =
ImmutableMap.of("primaryKey", primaryKey,
"sortKey", sortKey,
"creationDate", createDate,
"expireAt", expireDate);
final PutItemRequest request = PutItemRequest.builder()
.tableName(tableName)
.item((Map<String, AttributeValue>) itemMap)
.build();
try (DynamoDbClient ddb = DynamoDbClient.builder()
.region(region)
.build()) {
final PutItemResponse response = ddb.putItem(request);
System.out.println(tableName + " PutItem operation with TTL successful. Request id is "
+ response.responseMetadata().requestId());
} catch (ResourceNotFoundException e) {
System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
System.exit(1);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
System.exit(0);
}
}
- JavaScript
-
- SDK para JavaScript (v3)
-
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
function createDynamoDBItem(table_name, region, partition_key, sort_key) {
const client = new DynamoDBClient({
region: region,
endpoint: `https://dynamodb.${region}.amazonaws.com`
});
// Get the current time in epoch second format
const current_time = Math.floor(new Date().getTime() / 1000);
// Calculate the expireAt time (90 days from now) in epoch second format
const expire_at = Math.floor((new Date().getTime() + 90 * 24 * 60 * 60 * 1000) / 1000);
// Create DynamoDB item
const item = {
'partitionKey': {'S': partition_key},
'sortKey': {'S': sort_key},
'createdAt': {'N': current_time.toString()},
'expireAt': {'N': expire_at.toString()}
};
const putItemCommand = new PutItemCommand({
TableName: table_name,
Item: item,
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1,
},
});
client.send(putItemCommand, function(err, data) {
if (err) {
console.log("Exception encountered when creating item %s, here's what happened: ", data, ex);
throw err;
} else {
console.log("Item created successfully: %s.", data);
return data;
}
});
}
// use your own values
createDynamoDBItem('your-table-name', 'us-east-1', 'your-partition-key-value', 'your-sort-key-value');
- Python
-
- SDK para Python (Boto3)
-
import boto3
from datetime import datetime, timedelta
def create_dynamodb_item(table_name, region, primary_key, sort_key):
"""
Creates a DynamoDB item with an attached expiry attribute.
:param table_name: Table name for the boto3 resource to target when creating an item
:param region: string representing the AWS region. Example: `us-east-1`
:param primary_key: one attribute known as the partition key.
:param sort_key: Also known as a range attribute.
:return: Void (nothing)
"""
try:
dynamodb = boto3.resource('dynamodb', region_name=region)
table = dynamodb.Table(table_name)
# Get the current time in epoch second format
current_time = int(datetime.now().timestamp())
# Calculate the expiration time (90 days from now) in epoch second format
expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())
item = {
'primaryKey': primary_key,
'sortKey': sort_key,
'creationDate': current_time,
'expireAt': expiration_time
}
table.put_item(Item=item)
print("Item created successfully.")
except Exception as e:
print(f"Error creating item: {e}")
raise
# Use your own values
create_dynamodb_item('your-table-name', 'us-west-2', 'your-partition-key-value', 'your-sort-key-value')
Actualización de un elemento y del tiempo de vida
Este ejemplo es la continuación del que aparece en la sección anterior. La fecha de vencimiento se puede volver a calcular si se actualiza el elemento. En el siguiente ejemplo, se vuelve a calcular la marca de tiempo expireAt
para que sea de 90 días a partir de la fecha actual.
En los siguientes ejemplos de código, se muestra cómo actualizar el TTL de un elemento.
- Java
-
- SDK para Java 2.x
-
Actualice el TTL en un elemento de DynamoDB existente en una tabla.
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;
import software.amazon.awssdk.utils.ImmutableMap;
import java.util.Map;
import java.util.Optional;
// Get current time in epoch second format
final long currentTime = System.currentTimeMillis() / 1000;
// Calculate expiration time 90 days from now in epoch second format
final long expireDate = currentTime + (90 * 24 * 60 * 60);
// An expression that defines one or more attributes to be updated, the action to be performed on them, and new values for them.
final String updateExpression = "SET updatedAt=:c, expireAt=:e";
final ImmutableMap<String, AttributeValue> keyMap =
ImmutableMap.of("primaryKey", AttributeValue.fromS(primaryKey),
"sortKey", AttributeValue.fromS(sortKey));
final Map<String, AttributeValue> expressionAttributeValues = ImmutableMap.of(
":c", AttributeValue.builder().s(String.valueOf(currentTime)).build(),
":e", AttributeValue.builder().s(String.valueOf(expireDate)).build()
);
final UpdateItemRequest request = UpdateItemRequest.builder()
.tableName(tableName)
.key(keyMap)
.updateExpression(updateExpression)
.expressionAttributeValues(expressionAttributeValues)
.build();
try (DynamoDbClient ddb = DynamoDbClient.builder()
.region(region)
.build()) {
final UpdateItemResponse response = ddb.updateItem(request);
System.out.println(tableName + " UpdateItem operation with TTL successful. Request id is "
+ response.responseMetadata().requestId());
} catch (ResourceNotFoundException e) {
System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
System.exit(1);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
System.exit(0);
- JavaScript
-
- SDK para JavaScript (v3)
-
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
async function updateDynamoDBItem(tableName, region, partitionKey, sortKey) {
const client = new DynamoDBClient({
region: region,
endpoint: `https://dynamodb.${region}.amazonaws.com`
});
const currentTime = Math.floor(Date.now() / 1000);
const expireAt = Math.floor((Date.now() + 90 * 24 * 60 * 60 * 1000) / 1000);
const params = {
TableName: tableName,
Key: marshall({
partitionKey: partitionKey,
sortKey: sortKey
}),
UpdateExpression: "SET updatedAt = :c, expireAt = :e",
ExpressionAttributeValues: marshall({
":c": currentTime,
":e": expireAt
}),
};
try {
const data = await client.send(new UpdateItemCommand(params));
const responseData = unmarshall(data.Attributes);
console.log("Item updated successfully: %s", responseData);
return responseData;
} catch (err) {
console.error("Error updating item:", err);
throw err;
}
}
//enter your values here
updateDynamoDBItem('your-table-name', 'us-east-1', 'your-partition-key-value', 'your-sort-key-value');
- Python
-
- SDK para Python (Boto3)
-
import boto3
from datetime import datetime, timedelta
def update_dynamodb_item(table_name, region, primary_key, sort_key):
"""
Update an existing DynamoDB item with a TTL.
:param table_name: Name of the DynamoDB table
:param region: AWS Region of the table - example `us-east-1`
:param primary_key: one attribute known as the partition key.
:param sort_key: Also known as a range attribute.
:return: Void (nothing)
"""
try:
# Create the DynamoDB resource.
dynamodb = boto3.resource('dynamodb', region_name=region)
table = dynamodb.Table(table_name)
# Get the current time in epoch second format
current_time = int(datetime.now().timestamp())
# Calculate the expireAt time (90 days from now) in epoch second format
expire_at = int((datetime.now() + timedelta(days=90)).timestamp())
table.update_item(
Key={
'partitionKey': primary_key,
'sortKey': sort_key
},
UpdateExpression="set updatedAt=:c, expireAt=:e",
ExpressionAttributeValues={
':c': current_time,
':e': expire_at
},
)
print("Item updated successfully.")
except Exception as e:
print(f"Error updating item: {e}")
# Replace with your own values
update_dynamodb_item('your-table-name', 'us-west-2', 'your-partition-key-value', 'your-sort-key-value')
Los ejemplos de TTL que se analizan en esta introducción muestran un método para garantizar que en la tabla solo se guarden los elementos actualizados recientemente. La vida útil de los elementos actualizados se prolonga, mientras que los que no se actualizan tras su creación caducan y se eliminan sin costo alguno, lo que reduce el almacenamiento y mantiene las tablas limpias.