Skip to content

Instantly share code, notes, and snippets.

@mficzel
Last active September 4, 2020 08:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mficzel/c49eda754f7512536ccb855060fca53b to your computer and use it in GitHub Desktop.
Save mficzel/c49eda754f7512536ccb855060fca53b to your computer and use it in GitHub Desktop.
Neos Caching 101

Caching is hard but worth the hassle

Motivation

  • no clear cache button
  • 100 % transparent for editors
  • good caching makes sites fast

We are forced to configure caching right as otherwise editors will complain

https://docs.neos.io/cms/manual/rendering/caching

What is cached

  • Fusion has a static syntax tree and each branch can evaluated seperately for a specific context
  • Same path and context should result in the same value.
  • The results of each branch/leave can be cached (for a given set of identifiers)
  • When evaluating any branch fusion checks first wether there is a cache entry alredy
  • Cached entries
    • Value for the fusion path
    • Can have a due date (may be 0)
    • Can have tags to mark when they are be thrown away before the due date
  • !!! Fusion cache entries are always strings !!!
  • embed ... into parent cache entry
  • cached ... control maximumLifetime, entryIdentifier (find entry again), entryTags (when to delete)
  • uncached ... control context as only those values will be available for partial reevaluation
  • dynamic ... control entryDiscriminator false >> like uncached, "strings" >> multiple cached fragments
  • ${Neos.Caching.nodeTypeTag('[My.Package:NodeTypeName]', node)} : Flushes cache entries if any node with the given node type changes.
  • ${Neos.Caching.nodeTag(node)} : Flushes cache entries if the node changes
  • ${Neos.Caching.descendantOfTag(node)} : Flushes cache entries if a child node of the node changes.
  • "anyStringCanBeUsedAsTag" : You have to ensure calling flushByTag for this cache-tag yourself via signal, aspect etc.

Default.fusion

root {
  
	#  
	# render the fusion prototype that is named like the document type
	#

	@cache {
		mode = 'cached'

		entryIdentifier {
			node = ${node}
		}
		entryTags {
			# Whenever the node changes the matched condition could change
			1 = ${Neos.Caching.nodeTag(documentNode)}
			# Whenever one of the parent nodes changes the layout could change
			2 = ${Neos.Caching.nodeTag(q(documentNode).parents())}
		}
	}
}

Quelle: https://github.com/neos/neos-development-collection/blob/master/Neos.Neos/Resources/Private/Fusion/DefaultFusion.fusion#L72-L83

Neos.Neos:ContentCollection

prototype(Neos.Neos:ContentCollection) < prototype(Neos.Fusion:Tag) {
	
	# 
	# rendering of content collection
	#

	@cache {
		mode = 'cached'

		entryIdentifier {
			collection = ${node}
		}

		entryTags {
			1 = ${Neos.Caching.descendantOfTag(node)}
			2 = ${Neos.Caching.nodeTag(node)}
		}

		maximumLifetime = ${q(node).context({'invisibleContentShown': true}).children().cacheLifetime()}
	}

	@exceptionHandler = 'Neos\\Neos\\Fusion\\ExceptionHandlers\\NodeWrappingHandler'
}

#
# no caching for nested collections 
#
prototype(Neos.Neos:ContentCollection) {
	prototype(Neos.Neos:ContentCollection) {
		@cache {
			mode = 'embed'
		}
	}
}

Quelle: Neos.Neos:ContentCollection

Neos.Fusion:GlobalCacheIdentifiers

prototype(Neos.Fusion:GlobalCacheIdentifiers) {
	workspaceChain = ${documentNode.context.workspace.name + ',' + Array.join(Array.keys(documentNode.context.workspace.baseWorkspaces), ',')}
	editPreviewMode = ${documentNode.context.currentRenderingMode.name}
}

Quelle: https://github.com/neos/neos-development-collection/blob/master/Neos.Neos/Resources/Private/Fusion/DefaultFusion.fusion#L121-L124

Helpers and Tips

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment