Getting Started with Hazelcast Go Client
Start a Hazelcast Member
We will use the 5.0 version of Hazelcast for this tutorial.
In this tutorial, we will use Docker for simplicity. You can find the different installation methods here.
docker run --name hazelcast -p 5701:5701 hazelcast/hazelcast:5.0
This will start a new Hazelcast member at port 5701. Now, we have a Hazelcast cluster with just one member.
Start using Hazelcast Go Client
Create a new folder and navigate to it:
mkdir go-client-getting-started
cd go-client-getting-started
Initialize a new go module to start working on with any module name you prefer:
go mod init example
Add Hazelcast Go Client’s latest version as a dependency:
go get github.com/hazelcast/hazelcast-go-client@latest
We are ready to start experimenting with Go Client. Let’s create a go file:
touch map.go
Copy and paste the following code:
package main
import (
"context"
"fmt"
"log"
"github.com/hazelcast/hazelcast-go-client"
)
func main() {
ctx := context.TODO()
// create the client and connect to the cluster
client, err := hazelcast.StartNewClient(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(client.Name())
}
To run this go project, use the following command:
go run map.go
The following line creates and starts a new Hazelcast client with the default configuration.
client, err := hazelcast.StartNewClient(ctx)
The client automatically connects to the Hazelcast member available on the local machine, in our case the docker instance.
Use a Map
A Hazelcast map is a distributed key-value store, similar to built-in map type in Go. You can store key-value pairs in a map. In the following example, we will work with map entries where the keys are session ids and the values are emails.
package main
import (
"context"
"fmt"
"log"
"github.com/hazelcast/hazelcast-go-client"
)
func main() {
ctx := context.TODO()
client, err := hazelcast.StartNewClient(ctx)
if err != nil {
log.Fatal(err)
}
// get a map
emails, err := client.GetMap(ctx, "emails")
if err != nil {
log.Fatal(err)
}
// set a value in the map
if err := emails.Set(ctx, "sid12345", "example1@email.com"); err != nil {
log.Fatal(err)
}
if err := emails.Set(ctx, "sid12346", "example2@email.com"); err != nil {
log.Fatal(err)
}
// get a value from the map
email1, err := emails.Get(ctx, "sid12345")
if err != nil {
log.Fatal(err)
}
email2, err := emails.Get(ctx, "sid12346")
if err != nil {
log.Fatal(err)
}
fmt.Println(email1)
fmt.Println(email2)
// stop the client to release resources
client.Shutdown(ctx)
}
The output of this snippet is given below:
example1@email.com
example2@email.com
The following line returns a map proxy for the 'emails' map:
emails, err := client.GetMap(ctx, "emails")
If the map called “emails” does not exist in the Hazelcast cluster, it will be automatically created. All the clients that connect to the same cluster will have access to the same map.
With these lines, the Go client adds data to the map. The first parameter is context. Go client supports the Go context package. Most methods have the context as the first parameter. Check out the Go context documentation here. The second parameter is the key of the entry, the third one is the value:
emails.Set(ctx, "sid12345", "example1@email.com")
emails.Set(ctx, "sid12346", "example2@email.com")
Finally, we get the values we added to the map with the get method:
email1, err := emails.Get(ctx, "sid12345")
email2, err := emails.Get(ctx, "sid12346")
Add a Listener to the Map
You can add an entry listener using the “AddEntryListener” method available on map proxy. This will allow you to listen to certain events that happen in the map across the cluster.
The first argument being a context instance as we discussed before, the second argument to the “AddEntryListener” method is a configuration of type "MapEntryListenerConfig". This contains options to filter the events by key and/or predicate and has an option to include the value of the entry, not just the key. You should also choose which type of events you want to receive. In this example, we registered listeners for “added”, “removed" and “updated” events and we listen for all of the keys. Third argument is a function parameter that is called every time an enabled event is received. In this example we implement a switch-case to differantiate event types.
package main
import (
"context"
"fmt"
"log"
"github.com/hazelcast/hazelcast-go-client"
)
func main() {
// error handling was omitted for brevity
ctx := context.TODO()
client, err := hazelcast.StartNewClient(ctx)
if err != nil {
log.Fatal(err)
}
entryListenerConfig := hazelcast.MapEntryListenerConfig{
IncludeValue: true,
}
emails, err := client.GetMap(ctx, "emails")
if err != nil {
log.Fatal(err)
}
emails.Clear(ctx)
// enable receiving entry added events
entryListenerConfig.NotifyEntryAdded(true)
// enable receiving entry removed events
entryListenerConfig.NotifyEntryRemoved(true)
// enable receiving entry updated events
entryListenerConfig.NotifyEntryUpdated(true)
subscriptionID, err := emails.AddEntryListener(ctx, entryListenerConfig, func(event *hazelcast.EntryNotified) {
switch event.EventType {
// this is an entry added event
case hazelcast.EntryAdded:
fmt.Println("Entry Added:", event.Value)
// this is an entry removed event
case hazelcast.EntryRemoved:
fmt.Println("Entry Removed with key:", event.Key)
// this is an entry updated event
case hazelcast.EntryUpdated:
fmt.Println("Entry Updated from", event.Value, "to", event.OldValue)
}
})
if err != nil {
log.Fatal(err)
}
if err := emails.Set(ctx, "sid12345", "example1@email.com"); err != nil {
log.Fatal(err)
}
if err := emails.Set(ctx, "sid12346", "example2@email.com"); err != nil {
log.Fatal(err)
}
email1, err := emails.Get(ctx, "sid12345")
if err != nil {
log.Fatal(err)
}
email2, err := emails.Get(ctx, "sid12346")
if err != nil {
log.Fatal(err)
}
fmt.Println("Email1:", email1)
fmt.Println("Email2:", email2)
if err := emails.Delete(ctx, "sid12345"); err != nil {
log.Fatal(err)
}
if err := emails.Set(ctx, "sid12346", "example1@email.com"); err != nil {
log.Fatal(err)
}
email1, err = emails.Get(ctx, "sid12345")
if err != nil {
log.Fatal(err)
}
email2, err = emails.Get(ctx, "sid12346")
if err != nil {
log.Fatal(err)
}
fmt.Println("Email1:", email1)
fmt.Println("Email2:", email2)
// you can use the subscriptionID later to remove the event listener.
if err := emails.RemoveEntryListener(ctx, subscriptionID); err != nil {
log.Fatal(err)
}
}
First, the map is cleared to fire events even if there are some entries in the map. Then, two session entries are added, and they are logged. After that, we remove one of the entries and update the other one. Then, we log the session entries again.
The output is as follows:
Entry Added: example1@email.com
Entry Added: example2@email.com
Email1: example1@email.com
Email2: example2@email.com
Entry Removed with key: sid12345
Entry Updated from example1@email.com to example2@email.com
<nil>
example1@email.com
The value of the first entry becomes “nil” since it is removed.
Summary
In this tutorial, you learned how to get started with Hazelcast Go Client using a distributed map.
See Also
There are a lot of things that you can do with the Go client. For more, such as how you can query a map with predicates, check out our Go client repository. or jump straight to the documentation.
If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via Hazelcast Community Slack. Also, please take a look at the issue list if you would like to contribute to the client.