Sobes.tech

Golang

¿Tiene experiencia trabajando con sistemas distribuidos?

215

/* Hay dos servidores PostgreSQL: * PROD - servidor OLTP, * STATS - servidor para consultas analíticas prolongadas. En el servidor actual, en la base de datos prod, hay una tabla grande (10Tb) de la siguiente forma: CREATE TABLE profiles( id SERIAL, data JSONB ) En la tabla pueden haber "agujeros", es decir, algunos `id` pueden estar ausentes. Se necesita escribir un programa para copiar la tabla profiles desde PROD a STATS. Se supone que se usarán las siguientes interfaces para trabajar con bases de datos: type Row []interface{} type Database interface { // la implementación de la interfaz Database puede volver a establecer conexiones // la llamada a SaveRows es idempotente io.Closer GetMaxID(ctx context.Context) (uint64, error) LoadRows(ctx context.Context, minID, maxID uint64) ([]Row, error) // [minID, maxID] SaveRows(ctx context.Context, rows []Row) error } func Connect(ctx context.Context, dbname string) (Database, error) // CopyTable // Si full=false, continuar la transferencia de datos desde el lugar del error anterior // Si full=true, transferir todos los datos func CopyTable(fromName string, toName string, full bool) error { // ... tu código } Si se pasa la opción `full=false`, el programa debe continuar la transferencia de datos desde el lugar del error anterior. Si `full=true`, debe transferir todos los datos. **Nivel básico**: - transferencia secuencial de datos en un solo hilo - recuperación ante fallos (opción `full=false`) Información adicional: - si es necesario, puedes ampliar la interfaz agregando tus propios métodos - si es necesario, puedes usar directamente el paquete **database/sql**

215

Se da una cadena de caracteres. Encontrar la cantidad de pares de índices i y j (i <= j), entre los cuales, inclusive, no hay caracteres repetidos. Para la cadena "aba" la respuesta es 5: [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") Para la cadena "abcb" la respuesta es ?: aba 3 + 2 = 5 abcb 4 (a, b, c, d) + 1 (ab) + 1 (bc) + 1 (cb) + 1 (abc) = 8

213

/* Se da una cadena de caracteres. Encontrar la cantidad de pares de índices i y j (i <= j), entre los cuales no hay caracteres repetidos. Para la cadena "aba" la respuesta es 5: pueden ser no solo ASCII [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") */

213

/* Necesitamos transferir datos desde una fuente a un consumidor. La fuente entrega los datos en pequeños lotes (~diez registros), mientras que el consumidor funciona mejor con lotes grandes (~mil registros). Un ejemplo real es la transferencia de datos desde colas tipo Kafka a una base de datos Clickhouse. Fuente: - Prácticamente infinita. - La fuente nunca devuelve más de MaxItems registros en una llamada a Next. - Dentro de una "sesión" (una llamada a la función Pipe), la fuente devuelve datos nuevos en cada llamada a Next. - Sin embargo, tras reiniciar, la fuente comienza desde la posición "confirmada" anterior, indicada por cookie. Por lo tanto, *cada* valor de cookie devuelto por Next, después de guardar los datos en el receptor, debe ser confirmado con la llamada a Commit, en el mismo orden en que fueron devueltos por Next. Receptor: - No puede procesar más de MaxItems a la vez. Nivel básico: Se requiere implementar la función func Pipe(p Producer, c Consumer) error que lee datos de la fuente, los agrupa en un buffer de tamaño no mayor que MaxItems y los guarda en el receptor, después de lo cual confirma el progreso en la fuente. Dificultad adicional: Los métodos Next, Process y Commit están relacionados con llamadas de red y pueden tardar bastante. Para acelerar el proceso, es necesario paralelizar los procesos de lectura, escritura y confirmación del progreso. De modo que, durante Process o Commit, la lectura de la fuente y la formación del nuevo buffer continúen. */ const MaxItems = 9999 type Producer interface { // Next devuelve: // - un lote de items para procesar // - una cookie para confirmar cuando se complete el procesamiento // - un error Next() (items []any, cookie int, err error) // Commit se usa para marcar un lote de datos como procesado Commit(cookie int) error } type Consumer interface { Process(items []any) error } func Pipe(p Producer, c Consumer) error { // TODO }

213

Explica el principio de inversión de dependencias y por qué la llamada directa a los métodos del repositorio desde un caso de uso viola SOLID.

212

Cuéntame sobre bases de datos: ¿con cuáles has trabajado y con cuáles trabajas ahora?

212

¿En qué se diferencian los entornos local, dev, stage, prod?

211

¿Cómo realizaste la prueba y verificación de la corrección de las solicitudes realizadas?

Junior — Middle
211

/* Hay una aplicación con arquitectura de microservicios. Un microservicio puede abstraerse mediante una interfaz Backend. Para acceder a una instancia del microservicio, se puede usar el tipo BackendImpl, que ya está implementado. Cada microservicio tiene varias decenas de instancias en ejecución, cada una accesible por su propia dirección addr. Sin embargo, las instancias individuales del microservicio no son confiables: pueden fallar, estar inaccesibles o sobrecargadas. Por eso, necesitas implementar un tipo Balancer, que también implemente la interfaz Backend y realice balanceo de carga del lado del cliente entre las instancias del microservicio, eligiendo cada vez la instancia **menos cargada**. */

210

¿Cómo verifica JWT su autenticidad? ¿Cómo se asegura de que el token no sea falsificado?

210

/* Hay una aplicación con arquitectura de microservicios. Un microservicio puede abstraerse mediante una interfaz Backend. Para acceder a una instancia del microservicio, se puede usar el tipo BackendImpl, que ya está implementado. Cada microservicio tiene varias decenas de instancias en ejecución, cada una accesible por su propia dirección addr. Sin embargo, las instancias individuales del microservicio no son confiables: pueden fallar, estar inaccesibles o sobrecargadas. Por eso, necesitas implementar el tipo Balancer, que también implementa la interfaz Backend y realiza balanceo de carga del lado del cliente entre las instancias del microservicio, eligiendo cada vez la instancia **menos cargada**. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr contiene ip:puerto de una instancia específica func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs contienen las direcciones de todas las instancias balanceadas func NewBalancer(addrs []string) *Balancer { // TODO }

209

¿Has tenido experiencia en la gestión de equipos?

208

¿Cuál es la limitación de un semáforo y un canal con búfer como soluciones para limitar las solicitudes paralelas?

208

¿Qué se añade a la respuesta cuando la ventana se vuelve válida?

207

¿Cómo comparar elementos en un mapa? ¿Cómo verificar si dos mapas son iguales?

205

¿Cuál es la cantidad máxima de solicitudes por segundo (RPS) que ha manejado el servicio de mayor carga?

204

Escribir un problema en el lenguaje Go — sección práctica (problemas de la vida real del desarrollador, sin algoritmos): mejorar o corregir un servicio. Duración — 1,5 horas.

204

¿Formato de trabajo: remoto, en oficina o híbrido?

203

¿Cómo hacer que la memoria sea constante (eliminar la dependencia del número de caracteres únicos)?

203
/11