· 9 min Progettare

Akka è morto, lunga vita a Pekko

Scala Pekko Akka JVM Migrazione

Un servizio Scala su Akka 2.6 in produzione da tre anni. La licenza cambia, le patch di sicurezza non arrivano più. Quello che segue è la migrazione pratica da Akka ad Apache Pekko: checklist, gotcha e lezioni dal campo.

Il cambio licenza di Akka

A settembre 2022, Lightbend ha annunciato che Akka 2.7 e tutte le versioni successive sarebbero state rilasciate sotto Business Source License (BSL 1.1). In pratica: l’uso commerciale di Akka richiede una licenza a pagamento. L’intera serie Akka 2.6.x è rimasta sotto Apache 2.0 fino all’end-of-life. La versione 2.6.21, rilasciata a giugno 2023 come ultimo fix critico, è l’ultima release della serie. Dalla 2.7 in poi, tutte le versioni sono sotto BSL 1.1. Le versioni BSL revertono automaticamente ad Apache 2.0 dopo 3 anni dalla data di rilascio, ma per chi necessita di patch tempestive questa clausola non risolve il problema. Dal 19 ottobre 2023, la serie 2.6.x è ufficialmente end-of-life: nessun aggiornamento futuro, ma la licenza resta Apache 2.0.

La decisione ha colpito un ecosistema ampio. Akka è la base di framework come Play e di migliaia di sistemi in produzione nel mondo JVM. Per chi gestisce sistemi in produzione basati su Akka, le opzioni sono tre:

  1. Restare su Akka 2.6.x. Funziona, ma significa usare una versione frozen: nessun aggiornamento, nessuna correzione. Per un sistema che deve girare per anni, non è sostenibile.

  2. Pagare la licenza commerciale. Opzione legittima per aziende che possono permetterselo. Non sempre compatibile con vincoli di budget o con la preferenza per dipendenze a licenza aperta.

  3. Migrare a un fork open-source. Cioè Apache Pekko.


Apache Pekko: il fork della community

Apache Pekko è nato come fork della serie Akka 2.6.x (l’ultima mantenuta sotto Apache 2.0) sotto la Apache Software Foundation. Il progetto è stato incubato e promosso a progetto top-level ASF nel maggio 2024. La licenza è Apache 2.0, senza ambiguità.

La versione Pekko 1.0.x è un fork diretto di Akka 2.6.x. L’API è identica: stesse classi, stessi pattern, stessi comportamenti. L’unica differenza è il namespace: org.apache.pekko invece di akka. Questo rende la migrazione meccanica: cerca e sostituisci.

La versione Pekko 1.1.x introduce evoluzioni proprie: nuove feature, ottimizzazioni, divergenze progressive da Akka. Per chi migra, il consiglio è partire da 1.0.x (migrazione pura) e poi valutare l’upgrade a 1.1.x separatamente.

L’ecosistema è completo:

  • Pekko HTTP (ex Akka HTTP): server e client HTTP
  • Pekko Connectors (ex Alpakka): connettori per Kafka, MongoDB, S3, ecc.
  • Pekko gRPC (ex Akka gRPC): supporto gRPC
  • Pekko Streams (ex Akka Streams): stream processing reattivo
  • Pekko Cluster (ex Akka Cluster): clustering e distribuzione

Tutti i moduli disponibili in Akka hanno un corrispettivo diretto in Pekko.


Checklist di migrazione

La checklist pratica seguita per migrare i servizi Scala da Akka a Pekko. La maggior parte dei passi è meccanica.

1. build.sbt: coordinate Maven

Tutte le dipendenze cambiano group ID e nome artefatto.

// Prima (Akka)
"com.typesafe.akka" %% "akka-actor-typed"   % "2.6.20"
"com.typesafe.akka" %% "akka-stream"        % "2.6.20"
"com.typesafe.akka" %% "akka-http"          % "10.2.10"
"com.typesafe.akka" %% "akka-stream-kafka" % "3.0.1"

// Dopo (Pekko)
"org.apache.pekko" %% "pekko-actor-typed"   % "1.0.3"
"org.apache.pekko" %% "pekko-stream"        % "1.0.3"
"org.apache.pekko" %% "pekko-http"          % "1.0.1"
"org.apache.pekko" %% "pekko-connectors-kafka" % "1.0.0"

Da notare: le versioni non sono allineate tra i moduli. pekko-actor-typed e pekko-stream seguono il versioning del core (1.0.x), mentre pekko-http e pekko-connectors-kafka hanno versioni proprie. Bisogna verificare ogni artefatto.

2. Import nei file Scala

Sostituzione diretta in tutti i file sorgente:

// Prima
import akka.actor.typed.ActorSystem
import akka.stream.scaladsl.Source
import akka.http.scaladsl.Http

// Dopo
import org.apache.pekko.actor.typed.ActorSystem
import org.apache.pekko.stream.scaladsl.Source
import org.apache.pekko.http.scaladsl.Http

In un editor con supporto regex, il comando è s/import akka\./import org.apache.pekko./g. Attenzione a non sostituire occorrenze in stringhe o commenti dove akka potrebbe comparire in contesti diversi.

3. application.conf

I namespace di configurazione cambiano da akka {} a pekko {}:

# Prima
akka {
  loglevel = "INFO"
  actor {
    provider = "local"
  }
  http {
    server {
      idle-timeout = 60s
    }
  }
}

# Dopo
pekko {
  loglevel = "INFO"
  actor {
    provider = "local"
  }
  http {
    server {
      idle-timeout = 60s
    }
  }
}

Questo vale anche per reference.conf se il progetto ne definisce uno. E vale per le configurazioni nei test.

4. CORS: libreria diversa

La libreria CORS per Akka HTTP (ch.megard %% akka-http-cors) non ha un equivalente diretto. In Pekko, il supporto CORS è fornito dal progetto Pekko stesso:

// Prima
"ch.megard" %% "akka-http-cors" % "1.2.0"
import ch.megard.akka.http.cors.scaladsl.CorsDirectives._

// Dopo
"org.apache.pekko" %% "pekko-http-cors" % "1.0.1"
import org.apache.pekko.http.cors.scaladsl.CorsDirectives._

Il cambio di organizzazione (ch.megard -> org.apache.pekko) è facile da dimenticare perché non segue il pattern meccanico degli altri artefatti.

5. Plugin SBT

Se il progetto usa sbt-native-packager o altri plugin legati all’ecosistema Akka, verificare che non tirino dentro dipendenze transitive di Akka. In particolare, sbt-native-packager è agnostico rispetto ad Akka/Pekko, quindi non richiede modifiche.


La migrazione nel progetto

Il sistema usa Scala/Akka in tre servizi:

  • c40-standardization: polling HTTP delle API telemetriche dei produttori di mezzi, normalizzazione dei dati, produzione su topic Kafka. Usa Akka HTTP client, Akka Streams, Akka Kafka (Alpakka).

  • c40-aggregation: pipeline di arricchimento che consuma tre topic Kafka (dati telemetrici, anagrafiche, assegnamenti), li unisce e produce un topic aggregato. Usa Akka Streams e Akka Kafka.

  • filemanager: document management system con API HTTP REST e storage su MongoDB. Usa Akka HTTP server, Akka Streams per lo streaming di file.

In totale la migrazione ha toccato circa 50 file tra sorgenti Scala, configurazioni e build files. La stragrande maggioranza del lavoro è stato un rename meccanico: akka -> pekko, com.typesafe.akka -> org.apache.pekko, Akka -> Pekko nei commenti.

Il tempo effettivo di migrazione è stato circa mezza giornata per tutti e tre i servizi. La maggior parte del tempo non è stata spesa sul rename, ma sulla verifica: compilazione, test, avvio dei container Docker, controllo che i servizi rispondessero correttamente.

Gotcha 1: Apicurio 3.x ha rinominato gli artefatti

Questo non è strettamente legato a Pekko, ma la migrazione Akka->Pekko è stata l’occasione per aggiornare anche le dipendenze Apicurio. In Apicurio 3.x l’artefatto per il serializer/deserializer Avro è cambiato:

// Apicurio 2.x
"io.apicurio" % "apicurio-registry-serdes-avro-serde" % "2.6.4.Final"

// Apicurio 3.x
"io.apicurio" % "apicurio-registry-avro-serde-kafka" % "3.0.4"

Inoltre, la classe di configurazione è stata spostata: SerdeConfig estende SchemaResolverConfig (che contiene le opzioni per la risoluzione degli schema). I package Java sono cambiati (io.apicurio.registry.serde.config.SerdeConfig in 3.x vs io.apicurio.registry.serde.SerdeConfig in 2.x). Se il codice referenzia direttamente queste classi per configurare l’URL del registry o la strategia di lookup, servono modifiche agli import.

Gotcha 2: Materializer con ActorSystem typed

In Akka 2.6+ e Pekko 1.0+, ActorSystem[T] estende ClassicActorSystemProvider, e nel companion object di Materializer esiste una conversione implicita da ClassicActorSystemProvider a Materializer. Nella maggior parte dei casi, avere un implicit val system: ActorSystem[Nothing] in scope è sufficiente per eseguire stream senza dichiarare un Materializer esplicito.

Il pattern esplicito resta necessario solo in casi particolari (ad esempio per controllare il lifecycle del materializer separatamente dal system):

implicit val system: ActorSystem[Nothing] = ActorSystem(Behaviors.empty, "my-system")
// Solo se serve un Materializer con lifecycle indipendente:
implicit val mat: Materializer = SystemMaterializer(system).materializer

Se il progetto usava Akka Classic con un ActorMaterializer esplicito (deprecato in Akka 2.6), la migrazione a Pekko è l’occasione per rimuoverlo e affidarsi alla conversione implicita.

Gotcha 3: reference.conf e namespace

Alcune librerie di terze parti (non Pekko) possono avere reference.conf che definiscono configurazioni sotto il namespace akka {}. Dopo la migrazione, queste configurazioni non vengono più lette da Pekko perché il framework cerca sotto pekko {}. Se un servizio si comporta in modo strano dopo la migrazione (timeout diversi, buffer size cambiati, logging diverso), la prima cosa da verificare è che tutti i reference.conf siano stati aggiornati.

Gotcha 4: librerie di terze parti che dipendono da Akka

Se il progetto usa librerie che hanno Akka come dipendenza transitiva, queste continueranno a tirare dentro i jar di Akka. Il risultato è un classpath con sia akka che pekko, che può causare conflitti. La soluzione è verificare l’albero delle dipendenze (sbt dependencyTree) e cercare versioni aggiornate delle librerie che supportano Pekko, oppure escludere esplicitamente le dipendenze Akka.


Demo

L’intero codice del progetto è disponibile nel repository pubblico: https://github.com/monte97/kafka-pekko

Il repository include un consumer Scala/Pekko che mostra l’integrazione Pekko + Avro + Apicurio Registry. Il consumer usa il serde nativo di Apicurio (AvroKafkaDeserializer) per consumare messaggi Avro da un topic, deserializzarli tramite il registry, e stamparli a console.

Per avviare la demo:

git clone https://github.com/monte97/kafka-pekko
cd kafka-pekko
docker compose up

Il consumer Scala si avvia insieme al producer Node.js e al consumer Python, tutti connessi allo stesso topic con schema Avro.


Conclusioni

La migrazione da Akka ad Apache Pekko si articola in quattro punti:

  1. Il contesto: il cambio licenza di Akka a BSL 1.1 rende la migrazione a Pekko la scelta principale per progetti open-source
  2. La checklist: coordinate Maven, import, application.conf, librerie CORS e plugin SBT - la maggior parte è un rename meccanico
  3. I gotcha: Apicurio 3.x, Materializer implicito, reference.conf di terze parti e dipendenze transitive sono i punti dove servono verifiche manuali
  4. Il costo reale: non è nel rename, ma nella verifica - per tre servizi e ~50 file, circa mezza giornata

Una volta su Pekko 1.0.x, si torna su un binario di rilascio attivo con bugfix, patch di sicurezza e nuove feature.


Risorse Utili

Hai bisogno di una revisione architetturale?

Scopri il servizio →

Ti è piaciuto questo articolo?

Articoli correlati

Modifica su GitHub